1 // Copyright 2009 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "bootstrapper.h" 31 #include "codegen-inl.h" 32 #include "compiler.h" 33 #include "debug.h" 34 #include "liveedit.h" 35 #include "oprofile-agent.h" 36 #include "prettyprinter.h" 37 #include "register-allocator-inl.h" 38 #include "rewriter.h" 39 #include "runtime.h" 40 #include "scopeinfo.h" 41 #include "stub-cache.h" 42 43 namespace v8 { 44 namespace internal { 45 46 #define __ ACCESS_MASM(masm_) 47 48 #ifdef DEBUG 49 50 Comment::Comment(MacroAssembler* masm, const char* msg) 51 : masm_(masm), msg_(msg) { 52 __ RecordComment(msg); 53 } 54 55 56 Comment::~Comment() { 57 if (msg_[0] == '[') __ RecordComment("]"); 58 } 59 60 #endif // DEBUG 61 62 #undef __ 63 64 65 CodeGenerator* CodeGeneratorScope::top_ = NULL; 66 67 68 DeferredCode::DeferredCode() 69 : masm_(CodeGeneratorScope::Current()->masm()), 70 statement_position_(masm_->current_statement_position()), 71 position_(masm_->current_position()) { 72 ASSERT(statement_position_ != RelocInfo::kNoPosition); 73 ASSERT(position_ != RelocInfo::kNoPosition); 74 75 CodeGeneratorScope::Current()->AddDeferred(this); 76 #ifdef DEBUG 77 comment_ = ""; 78 #endif 79 80 // Copy the register locations from the code generator's frame. 81 // These are the registers that will be spilled on entry to the 82 // deferred code and restored on exit. 83 VirtualFrame* frame = CodeGeneratorScope::Current()->frame(); 84 int sp_offset = frame->fp_relative(frame->stack_pointer_); 85 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { 86 int loc = frame->register_location(i); 87 if (loc == VirtualFrame::kIllegalIndex) { 88 registers_[i] = kIgnore; 89 } else if (frame->elements_[loc].is_synced()) { 90 // Needs to be restored on exit but not saved on entry. 91 registers_[i] = frame->fp_relative(loc) | kSyncedFlag; 92 } else { 93 int offset = frame->fp_relative(loc); 94 registers_[i] = (offset < sp_offset) ? kPush : offset; 95 } 96 } 97 } 98 99 100 void CodeGenerator::ProcessDeferred() { 101 while (!deferred_.is_empty()) { 102 DeferredCode* code = deferred_.RemoveLast(); 103 ASSERT(masm_ == code->masm()); 104 // Record position of deferred code stub. 105 masm_->RecordStatementPosition(code->statement_position()); 106 if (code->position() != RelocInfo::kNoPosition) { 107 masm_->RecordPosition(code->position()); 108 } 109 // Generate the code. 110 Comment cmnt(masm_, code->comment()); 111 masm_->bind(code->entry_label()); 112 code->SaveRegisters(); 113 code->Generate(); 114 code->RestoreRegisters(); 115 masm_->jmp(code->exit_label()); 116 } 117 } 118 119 120 void CodeGenerator::SetFrame(VirtualFrame* new_frame, 121 RegisterFile* non_frame_registers) { 122 RegisterFile saved_counts; 123 if (has_valid_frame()) { 124 frame_->DetachFromCodeGenerator(); 125 // The remaining register reference counts are the non-frame ones. 126 allocator_->SaveTo(&saved_counts); 127 } 128 129 if (new_frame != NULL) { 130 // Restore the non-frame register references that go with the new frame. 131 allocator_->RestoreFrom(non_frame_registers); 132 new_frame->AttachToCodeGenerator(); 133 } 134 135 frame_ = new_frame; 136 saved_counts.CopyTo(non_frame_registers); 137 } 138 139 140 void CodeGenerator::DeleteFrame() { 141 if (has_valid_frame()) { 142 frame_->DetachFromCodeGenerator(); 143 frame_ = NULL; 144 } 145 } 146 147 148 void CodeGenerator::MakeCodePrologue(CompilationInfo* info) { 149 #ifdef DEBUG 150 bool print_source = false; 151 bool print_ast = false; 152 bool print_json_ast = false; 153 const char* ftype; 154 155 if (Bootstrapper::IsActive()) { 156 print_source = FLAG_print_builtin_source; 157 print_ast = FLAG_print_builtin_ast; 158 print_json_ast = FLAG_print_builtin_json_ast; 159 ftype = "builtin"; 160 } else { 161 print_source = FLAG_print_source; 162 print_ast = FLAG_print_ast; 163 print_json_ast = FLAG_print_json_ast; 164 ftype = "user-defined"; 165 } 166 167 if (FLAG_trace_codegen || print_source || print_ast) { 168 PrintF("*** Generate code for %s function: ", ftype); 169 info->function()->name()->ShortPrint(); 170 PrintF(" ***\n"); 171 } 172 173 if (print_source) { 174 PrintF("--- Source from AST ---\n%s\n", 175 PrettyPrinter().PrintProgram(info->function())); 176 } 177 178 if (print_ast) { 179 PrintF("--- AST ---\n%s\n", 180 AstPrinter().PrintProgram(info->function())); 181 } 182 183 if (print_json_ast) { 184 JsonAstBuilder builder; 185 PrintF("%s", builder.BuildProgram(info->function())); 186 } 187 #endif // DEBUG 188 } 189 190 191 Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm, 192 Code::Flags flags, 193 CompilationInfo* info) { 194 // Allocate and install the code. 195 CodeDesc desc; 196 masm->GetCode(&desc); 197 ZoneScopeInfo sinfo(info->scope()); 198 Handle<Code> code = 199 Factory::NewCode(desc, &sinfo, flags, masm->CodeObject()); 200 201 #ifdef ENABLE_DISASSEMBLER 202 bool print_code = Bootstrapper::IsActive() 203 ? FLAG_print_builtin_code 204 : FLAG_print_code; 205 if (print_code) { 206 // Print the source code if available. 207 Handle<Script> script = info->script(); 208 FunctionLiteral* function = info->function(); 209 if (!script->IsUndefined() && !script->source()->IsUndefined()) { 210 PrintF("--- Raw source ---\n"); 211 StringInputBuffer stream(String::cast(script->source())); 212 stream.Seek(function->start_position()); 213 // fun->end_position() points to the last character in the stream. We 214 // need to compensate by adding one to calculate the length. 215 int source_len = 216 function->end_position() - function->start_position() + 1; 217 for (int i = 0; i < source_len; i++) { 218 if (stream.has_more()) PrintF("%c", stream.GetNext()); 219 } 220 PrintF("\n\n"); 221 } 222 PrintF("--- Code ---\n"); 223 code->Disassemble(*function->name()->ToCString()); 224 } 225 #endif // ENABLE_DISASSEMBLER 226 227 if (!code.is_null()) { 228 Counters::total_compiled_code_size.Increment(code->instruction_size()); 229 } 230 return code; 231 } 232 233 234 // Generate the code. Takes a function literal, generates code for it, assemble 235 // all the pieces into a Code object. This function is only to be called by 236 // the compiler.cc code. 237 Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) { 238 LiveEditFunctionTracker live_edit_tracker(info->function()); 239 Handle<Script> script = info->script(); 240 if (!script->IsUndefined() && !script->source()->IsUndefined()) { 241 int len = String::cast(script->source())->length(); 242 Counters::total_old_codegen_source_size.Increment(len); 243 } 244 MakeCodePrologue(info); 245 // Generate code. 246 const int kInitialBufferSize = 4 * KB; 247 MacroAssembler masm(NULL, kInitialBufferSize); 248 CodeGenerator cgen(&masm); 249 CodeGeneratorScope scope(&cgen); 250 live_edit_tracker.RecordFunctionScope(info->function()->scope()); 251 cgen.Generate(info); 252 if (cgen.HasStackOverflow()) { 253 ASSERT(!Top::has_pending_exception()); 254 return Handle<Code>::null(); 255 } 256 257 InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP; 258 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop); 259 Handle<Code> result = MakeCodeEpilogue(cgen.masm(), flags, info); 260 live_edit_tracker.RecordFunctionCode(result); 261 return result; 262 } 263 264 265 #ifdef ENABLE_LOGGING_AND_PROFILING 266 267 bool CodeGenerator::ShouldGenerateLog(Expression* type) { 268 ASSERT(type != NULL); 269 if (!Logger::is_logging()) return false; 270 Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle()); 271 if (FLAG_log_regexp) { 272 static Vector<const char> kRegexp = CStrVector("regexp"); 273 if (name->IsEqualTo(kRegexp)) 274 return true; 275 } 276 return false; 277 } 278 279 #endif 280 281 282 Handle<Code> CodeGenerator::ComputeCallInitialize( 283 int argc, 284 InLoopFlag in_loop) { 285 if (in_loop == IN_LOOP) { 286 // Force the creation of the corresponding stub outside loops, 287 // because it may be used when clearing the ICs later - it is 288 // possible for a series of IC transitions to lose the in-loop 289 // information, and the IC clearing code can't generate a stub 290 // that it needs so we need to ensure it is generated already. 291 ComputeCallInitialize(argc, NOT_IN_LOOP); 292 } 293 CALL_HEAP_FUNCTION(StubCache::ComputeCallInitialize(argc, in_loop), Code); 294 } 295 296 297 void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) { 298 int length = declarations->length(); 299 int globals = 0; 300 for (int i = 0; i < length; i++) { 301 Declaration* node = declarations->at(i); 302 Variable* var = node->proxy()->var(); 303 Slot* slot = var->slot(); 304 305 // If it was not possible to allocate the variable at compile 306 // time, we need to "declare" it at runtime to make sure it 307 // actually exists in the local context. 308 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) { 309 VisitDeclaration(node); 310 } else { 311 // Count global variables and functions for later processing 312 globals++; 313 } 314 } 315 316 // Return in case of no declared global functions or variables. 317 if (globals == 0) return; 318 319 // Compute array of global variable and function declarations. 320 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED); 321 for (int j = 0, i = 0; i < length; i++) { 322 Declaration* node = declarations->at(i); 323 Variable* var = node->proxy()->var(); 324 Slot* slot = var->slot(); 325 326 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) { 327 // Skip - already processed. 328 } else { 329 array->set(j++, *(var->name())); 330 if (node->fun() == NULL) { 331 if (var->mode() == Variable::CONST) { 332 // In case this is const property use the hole. 333 array->set_the_hole(j++); 334 } else { 335 array->set_undefined(j++); 336 } 337 } else { 338 Handle<JSFunction> function = 339 Compiler::BuildBoilerplate(node->fun(), script(), this); 340 // Check for stack-overflow exception. 341 if (HasStackOverflow()) return; 342 array->set(j++, *function); 343 } 344 } 345 } 346 347 // Invoke the platform-dependent code generator to do the actual 348 // declaration the global variables and functions. 349 DeclareGlobals(array); 350 } 351 352 353 354 // Special cases: These 'runtime calls' manipulate the current 355 // frame and are only used 1 or two places, so we generate them 356 // inline instead of generating calls to them. They are used 357 // for implementing Function.prototype.call() and 358 // Function.prototype.apply(). 359 CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = { 360 {&CodeGenerator::GenerateIsSmi, "_IsSmi"}, 361 {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"}, 362 {&CodeGenerator::GenerateIsArray, "_IsArray"}, 363 {&CodeGenerator::GenerateIsRegExp, "_IsRegExp"}, 364 {&CodeGenerator::GenerateIsConstructCall, "_IsConstructCall"}, 365 {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"}, 366 {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"}, 367 {&CodeGenerator::GenerateClassOf, "_ClassOf"}, 368 {&CodeGenerator::GenerateValueOf, "_ValueOf"}, 369 {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"}, 370 {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"}, 371 {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"}, 372 {&CodeGenerator::GenerateLog, "_Log"}, 373 {&CodeGenerator::GenerateRandomPositiveSmi, "_RandomPositiveSmi"}, 374 {&CodeGenerator::GenerateIsObject, "_IsObject"}, 375 {&CodeGenerator::GenerateIsFunction, "_IsFunction"}, 376 {&CodeGenerator::GenerateIsUndetectableObject, "_IsUndetectableObject"}, 377 {&CodeGenerator::GenerateStringAdd, "_StringAdd"}, 378 {&CodeGenerator::GenerateSubString, "_SubString"}, 379 {&CodeGenerator::GenerateStringCompare, "_StringCompare"}, 380 {&CodeGenerator::GenerateRegExpExec, "_RegExpExec"}, 381 {&CodeGenerator::GenerateNumberToString, "_NumberToString"}, 382 {&CodeGenerator::GenerateMathSin, "_Math_sin"}, 383 {&CodeGenerator::GenerateMathCos, "_Math_cos"}, 384 }; 385 386 387 CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT( 388 Handle<String> name) { 389 const int entries_count = 390 sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT); 391 for (int i = 0; i < entries_count; i++) { 392 InlineRuntimeLUT* entry = &kInlineRuntimeLUT[i]; 393 if (name->IsEqualTo(CStrVector(entry->name))) { 394 return entry; 395 } 396 } 397 return NULL; 398 } 399 400 401 bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) { 402 ZoneList<Expression*>* args = node->arguments(); 403 Handle<String> name = node->name(); 404 if (name->length() > 0 && name->Get(0) == '_') { 405 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name); 406 if (entry != NULL) { 407 ((*this).*(entry->method))(args); 408 return true; 409 } 410 } 411 return false; 412 } 413 414 415 bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name, 416 const CodeGenerator::InlineRuntimeLUT& new_entry, 417 CodeGenerator::InlineRuntimeLUT* old_entry) { 418 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name); 419 if (entry == NULL) return false; 420 if (old_entry != NULL) { 421 old_entry->name = entry->name; 422 old_entry->method = entry->method; 423 } 424 entry->name = new_entry.name; 425 entry->method = new_entry.method; 426 return true; 427 } 428 429 430 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a 431 // known result for the test expression, with no side effects. 432 CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition( 433 Expression* cond) { 434 if (cond == NULL) return ALWAYS_TRUE; 435 436 Literal* lit = cond->AsLiteral(); 437 if (lit == NULL) return DONT_KNOW; 438 439 if (lit->IsTrue()) { 440 return ALWAYS_TRUE; 441 } else if (lit->IsFalse()) { 442 return ALWAYS_FALSE; 443 } 444 445 return DONT_KNOW; 446 } 447 448 449 void CodeGenerator::RecordPositions(MacroAssembler* masm, int pos) { 450 if (pos != RelocInfo::kNoPosition) { 451 masm->RecordStatementPosition(pos); 452 masm->RecordPosition(pos); 453 } 454 } 455 456 457 void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) { 458 if (FLAG_debug_info) RecordPositions(masm(), fun->start_position()); 459 } 460 461 462 void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) { 463 if (FLAG_debug_info) RecordPositions(masm(), fun->end_position()); 464 } 465 466 467 void CodeGenerator::CodeForStatementPosition(Statement* stmt) { 468 if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos()); 469 } 470 471 void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) { 472 if (FLAG_debug_info) RecordPositions(masm(), stmt->condition_position()); 473 } 474 475 void CodeGenerator::CodeForSourcePosition(int pos) { 476 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) { 477 masm()->RecordPosition(pos); 478 } 479 } 480 481 482 const char* GenericUnaryOpStub::GetName() { 483 switch (op_) { 484 case Token::SUB: 485 return overwrite_ 486 ? "GenericUnaryOpStub_SUB_Overwrite" 487 : "GenericUnaryOpStub_SUB_Alloc"; 488 case Token::BIT_NOT: 489 return overwrite_ 490 ? "GenericUnaryOpStub_BIT_NOT_Overwrite" 491 : "GenericUnaryOpStub_BIT_NOT_Alloc"; 492 default: 493 UNREACHABLE(); 494 return "<unknown>"; 495 } 496 } 497 498 499 void ArgumentsAccessStub::Generate(MacroAssembler* masm) { 500 switch (type_) { 501 case READ_LENGTH: GenerateReadLength(masm); break; 502 case READ_ELEMENT: GenerateReadElement(masm); break; 503 case NEW_OBJECT: GenerateNewObject(masm); break; 504 } 505 } 506 507 508 int CEntryStub::MinorKey() { 509 ASSERT(result_size_ <= 2); 510 #ifdef _WIN64 511 return ExitFrameModeBits::encode(mode_) 512 | IndirectResultBits::encode(result_size_ > 1); 513 #else 514 return ExitFrameModeBits::encode(mode_); 515 #endif 516 } 517 518 519 bool ApiGetterEntryStub::GetCustomCache(Code** code_out) { 520 Object* cache = info()->load_stub_cache(); 521 if (cache->IsUndefined()) { 522 return false; 523 } else { 524 *code_out = Code::cast(cache); 525 return true; 526 } 527 } 528 529 530 void ApiGetterEntryStub::SetCustomCache(Code* value) { 531 info()->set_load_stub_cache(value); 532 } 533 534 535 } } // namespace v8::internal 536