1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/v8.h" 6 7 #include "src/bootstrapper.h" 8 #include "src/codegen.h" 9 #include "src/compiler.h" 10 #include "src/cpu-profiler.h" 11 #include "src/debug.h" 12 #include "src/prettyprinter.h" 13 #include "src/rewriter.h" 14 #include "src/runtime.h" 15 #include "src/stub-cache.h" 16 17 namespace v8 { 18 namespace internal { 19 20 21 #if defined(_WIN64) 22 typedef double (*ModuloFunction)(double, double); 23 static ModuloFunction modulo_function = NULL; 24 // Defined in codegen-x64.cc. 25 ModuloFunction CreateModuloFunction(); 26 27 void init_modulo_function() { 28 modulo_function = CreateModuloFunction(); 29 } 30 31 32 double modulo(double x, double y) { 33 // Note: here we rely on dependent reads being ordered. This is true 34 // on all architectures we currently support. 35 return (*modulo_function)(x, y); 36 } 37 #elif defined(_WIN32) 38 39 double modulo(double x, double y) { 40 // Workaround MS fmod bugs. ECMA-262 says: 41 // dividend is finite and divisor is an infinity => result equals dividend 42 // dividend is a zero and divisor is nonzero finite => result equals dividend 43 if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) && 44 !(x == 0 && (y != 0 && std::isfinite(y)))) { 45 x = fmod(x, y); 46 } 47 return x; 48 } 49 #else // POSIX 50 51 double modulo(double x, double y) { 52 return std::fmod(x, y); 53 } 54 #endif // defined(_WIN64) 55 56 57 #define UNARY_MATH_FUNCTION(name, generator) \ 58 static UnaryMathFunction fast_##name##_function = NULL; \ 59 void init_fast_##name##_function() { \ 60 fast_##name##_function = generator; \ 61 } \ 62 double fast_##name(double x) { \ 63 return (*fast_##name##_function)(x); \ 64 } 65 66 UNARY_MATH_FUNCTION(exp, CreateExpFunction()) 67 UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) 68 69 #undef UNARY_MATH_FUNCTION 70 71 72 void lazily_initialize_fast_exp() { 73 if (fast_exp_function == NULL) { 74 init_fast_exp_function(); 75 } 76 } 77 78 79 #define __ ACCESS_MASM(masm_) 80 81 #ifdef DEBUG 82 83 Comment::Comment(MacroAssembler* masm, const char* msg) 84 : masm_(masm), msg_(msg) { 85 __ RecordComment(msg); 86 } 87 88 89 Comment::~Comment() { 90 if (msg_[0] == '[') __ RecordComment("]"); 91 } 92 93 #endif // DEBUG 94 95 #undef __ 96 97 98 void CodeGenerator::MakeCodePrologue(CompilationInfo* info, const char* kind) { 99 bool print_source = false; 100 bool print_ast = false; 101 const char* ftype; 102 103 if (info->isolate()->bootstrapper()->IsActive()) { 104 print_source = FLAG_print_builtin_source; 105 print_ast = FLAG_print_builtin_ast; 106 ftype = "builtin"; 107 } else { 108 print_source = FLAG_print_source; 109 print_ast = FLAG_print_ast; 110 ftype = "user-defined"; 111 } 112 113 if (FLAG_trace_codegen || print_source || print_ast) { 114 PrintF("[generating %s code for %s function: ", kind, ftype); 115 if (info->IsStub()) { 116 const char* name = 117 CodeStub::MajorName(info->code_stub()->MajorKey(), true); 118 PrintF("%s", name == NULL ? "<unknown>" : name); 119 } else { 120 PrintF("%s", info->function()->debug_name()->ToCString().get()); 121 } 122 PrintF("]\n"); 123 } 124 125 #ifdef DEBUG 126 if (!info->IsStub() && print_source) { 127 PrintF("--- Source from AST ---\n%s\n", 128 PrettyPrinter(info->zone()).PrintProgram(info->function())); 129 } 130 131 if (!info->IsStub() && print_ast) { 132 PrintF("--- AST ---\n%s\n", 133 AstPrinter(info->zone()).PrintProgram(info->function())); 134 } 135 #endif // DEBUG 136 } 137 138 139 Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm, 140 Code::Flags flags, 141 CompilationInfo* info) { 142 Isolate* isolate = info->isolate(); 143 144 // Allocate and install the code. 145 CodeDesc desc; 146 bool is_crankshafted = 147 Code::ExtractKindFromFlags(flags) == Code::OPTIMIZED_FUNCTION || 148 info->IsStub(); 149 masm->GetCode(&desc); 150 Handle<Code> code = 151 isolate->factory()->NewCode(desc, flags, masm->CodeObject(), 152 false, is_crankshafted, 153 info->prologue_offset(), 154 info->is_debug() && !is_crankshafted); 155 isolate->counters()->total_compiled_code_size()->Increment( 156 code->instruction_size()); 157 isolate->heap()->IncrementCodeGeneratedBytes(is_crankshafted, 158 code->instruction_size()); 159 return code; 160 } 161 162 163 void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) { 164 #ifdef ENABLE_DISASSEMBLER 165 AllowDeferredHandleDereference allow_deference_for_print_code; 166 bool print_code = info->isolate()->bootstrapper()->IsActive() 167 ? FLAG_print_builtin_code 168 : (FLAG_print_code || 169 (info->IsStub() && FLAG_print_code_stubs) || 170 (info->IsOptimizing() && FLAG_print_opt_code)); 171 if (print_code) { 172 // Print the source code if available. 173 FunctionLiteral* function = info->function(); 174 bool print_source = code->kind() == Code::OPTIMIZED_FUNCTION || 175 code->kind() == Code::FUNCTION; 176 177 CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer()); 178 if (print_source) { 179 Handle<Script> script = info->script(); 180 if (!script->IsUndefined() && !script->source()->IsUndefined()) { 181 PrintF(tracing_scope.file(), "--- Raw source ---\n"); 182 ConsStringIteratorOp op; 183 StringCharacterStream stream(String::cast(script->source()), 184 &op, 185 function->start_position()); 186 // fun->end_position() points to the last character in the stream. We 187 // need to compensate by adding one to calculate the length. 188 int source_len = 189 function->end_position() - function->start_position() + 1; 190 for (int i = 0; i < source_len; i++) { 191 if (stream.HasMore()) { 192 PrintF(tracing_scope.file(), "%c", stream.GetNext()); 193 } 194 } 195 PrintF(tracing_scope.file(), "\n\n"); 196 } 197 } 198 if (info->IsOptimizing()) { 199 if (FLAG_print_unopt_code) { 200 PrintF(tracing_scope.file(), "--- Unoptimized code ---\n"); 201 info->closure()->shared()->code()->Disassemble( 202 function->debug_name()->ToCString().get(), tracing_scope.file()); 203 } 204 PrintF(tracing_scope.file(), "--- Optimized code ---\n"); 205 PrintF(tracing_scope.file(), 206 "optimization_id = %d\n", info->optimization_id()); 207 } else { 208 PrintF(tracing_scope.file(), "--- Code ---\n"); 209 } 210 if (print_source) { 211 PrintF(tracing_scope.file(), 212 "source_position = %d\n", function->start_position()); 213 } 214 if (info->IsStub()) { 215 CodeStub::Major major_key = info->code_stub()->MajorKey(); 216 code->Disassemble(CodeStub::MajorName(major_key, false), 217 tracing_scope.file()); 218 } else { 219 code->Disassemble(function->debug_name()->ToCString().get(), 220 tracing_scope.file()); 221 } 222 PrintF(tracing_scope.file(), "--- End code ---\n"); 223 } 224 #endif // ENABLE_DISASSEMBLER 225 } 226 227 228 bool CodeGenerator::RecordPositions(MacroAssembler* masm, 229 int pos, 230 bool right_here) { 231 if (pos != RelocInfo::kNoPosition) { 232 masm->positions_recorder()->RecordStatementPosition(pos); 233 masm->positions_recorder()->RecordPosition(pos); 234 if (right_here) { 235 return masm->positions_recorder()->WriteRecordedPositions(); 236 } 237 } 238 return false; 239 } 240 241 242 void ArgumentsAccessStub::Generate(MacroAssembler* masm) { 243 switch (type_) { 244 case READ_ELEMENT: 245 GenerateReadElement(masm); 246 break; 247 case NEW_SLOPPY_FAST: 248 GenerateNewSloppyFast(masm); 249 break; 250 case NEW_SLOPPY_SLOW: 251 GenerateNewSloppySlow(masm); 252 break; 253 case NEW_STRICT: 254 GenerateNewStrict(masm); 255 break; 256 } 257 } 258 259 260 int CEntryStub::MinorKey() { 261 int result = (save_doubles_ == kSaveFPRegs) ? 1 : 0; 262 ASSERT(result_size_ == 1 || result_size_ == 2); 263 #ifdef _WIN64 264 return result | ((result_size_ == 1) ? 0 : 2); 265 #else 266 return result; 267 #endif 268 } 269 270 271 } } // namespace v8::internal 272