codegen.cc revision 9ac36c9faca11611ada13b4054edbaa0738661d0
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 "oprofile-agent.h" 35#include "prettyprinter.h" 36#include "register-allocator-inl.h" 37#include "rewriter.h" 38#include "runtime.h" 39#include "scopeinfo.h" 40#include "stub-cache.h" 41#include "virtual-frame-inl.h" 42 43namespace v8 { 44namespace internal { 45 46#define __ ACCESS_MASM(masm_) 47 48#ifdef DEBUG 49 50Comment::Comment(MacroAssembler* masm, const char* msg) 51 : masm_(masm), msg_(msg) { 52 __ RecordComment(msg); 53} 54 55 56Comment::~Comment() { 57 if (msg_[0] == '[') __ RecordComment("]"); 58} 59 60#endif // DEBUG 61 62#undef __ 63 64 65CodeGenerator* CodeGeneratorScope::top_ = NULL; 66 67 68void CodeGenerator::ProcessDeferred() { 69 while (!deferred_.is_empty()) { 70 DeferredCode* code = deferred_.RemoveLast(); 71 ASSERT(masm_ == code->masm()); 72 // Record position of deferred code stub. 73 masm_->RecordStatementPosition(code->statement_position()); 74 if (code->position() != RelocInfo::kNoPosition) { 75 masm_->RecordPosition(code->position()); 76 } 77 // Generate the code. 78 Comment cmnt(masm_, code->comment()); 79 masm_->bind(code->entry_label()); 80 if (code->AutoSaveAndRestore()) { 81 code->SaveRegisters(); 82 } 83 code->Generate(); 84 if (code->AutoSaveAndRestore()) { 85 code->RestoreRegisters(); 86 code->Exit(); 87 } 88 } 89} 90 91 92void DeferredCode::Exit() { 93 masm_->jmp(exit_label()); 94} 95 96 97void CodeGenerator::SetFrame(VirtualFrame* new_frame, 98 RegisterFile* non_frame_registers) { 99 RegisterFile saved_counts; 100 if (has_valid_frame()) { 101 frame_->DetachFromCodeGenerator(); 102 // The remaining register reference counts are the non-frame ones. 103 allocator_->SaveTo(&saved_counts); 104 } 105 106 if (new_frame != NULL) { 107 // Restore the non-frame register references that go with the new frame. 108 allocator_->RestoreFrom(non_frame_registers); 109 new_frame->AttachToCodeGenerator(); 110 } 111 112 frame_ = new_frame; 113 saved_counts.CopyTo(non_frame_registers); 114} 115 116 117void CodeGenerator::DeleteFrame() { 118 if (has_valid_frame()) { 119 frame_->DetachFromCodeGenerator(); 120 frame_ = NULL; 121 } 122} 123 124 125void CodeGenerator::MakeCodePrologue(CompilationInfo* info) { 126#ifdef DEBUG 127 bool print_source = false; 128 bool print_ast = false; 129 bool print_json_ast = false; 130 const char* ftype; 131 132 if (Bootstrapper::IsActive()) { 133 print_source = FLAG_print_builtin_source; 134 print_ast = FLAG_print_builtin_ast; 135 print_json_ast = FLAG_print_builtin_json_ast; 136 ftype = "builtin"; 137 } else { 138 print_source = FLAG_print_source; 139 print_ast = FLAG_print_ast; 140 print_json_ast = FLAG_print_json_ast; 141 ftype = "user-defined"; 142 } 143 144 if (FLAG_trace_codegen || print_source || print_ast) { 145 PrintF("*** Generate code for %s function: ", ftype); 146 info->function()->name()->ShortPrint(); 147 PrintF(" ***\n"); 148 } 149 150 if (print_source) { 151 PrintF("--- Source from AST ---\n%s\n", 152 PrettyPrinter().PrintProgram(info->function())); 153 } 154 155 if (print_ast) { 156 PrintF("--- AST ---\n%s\n", 157 AstPrinter().PrintProgram(info->function())); 158 } 159 160 if (print_json_ast) { 161 JsonAstBuilder builder; 162 PrintF("%s", builder.BuildProgram(info->function())); 163 } 164#endif // DEBUG 165} 166 167 168Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm, 169 Code::Flags flags, 170 CompilationInfo* info) { 171 // Allocate and install the code. 172 CodeDesc desc; 173 masm->GetCode(&desc); 174 Handle<Code> code = Factory::NewCode(desc, flags, masm->CodeObject()); 175 176#ifdef ENABLE_DISASSEMBLER 177 bool print_code = Bootstrapper::IsActive() 178 ? FLAG_print_builtin_code 179 : FLAG_print_code; 180 if (print_code) { 181 // Print the source code if available. 182 Handle<Script> script = info->script(); 183 FunctionLiteral* function = info->function(); 184 if (!script->IsUndefined() && !script->source()->IsUndefined()) { 185 PrintF("--- Raw source ---\n"); 186 StringInputBuffer stream(String::cast(script->source())); 187 stream.Seek(function->start_position()); 188 // fun->end_position() points to the last character in the stream. We 189 // need to compensate by adding one to calculate the length. 190 int source_len = 191 function->end_position() - function->start_position() + 1; 192 for (int i = 0; i < source_len; i++) { 193 if (stream.has_more()) PrintF("%c", stream.GetNext()); 194 } 195 PrintF("\n\n"); 196 } 197 PrintF("--- Code ---\n"); 198 code->Disassemble(*function->name()->ToCString()); 199 } 200#endif // ENABLE_DISASSEMBLER 201 202 if (!code.is_null()) { 203 Counters::total_compiled_code_size.Increment(code->instruction_size()); 204 } 205 return code; 206} 207 208 209// Generate the code. Takes a function literal, generates code for it, assemble 210// all the pieces into a Code object. This function is only to be called by 211// the compiler.cc code. 212Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) { 213 Handle<Script> script = info->script(); 214 if (!script->IsUndefined() && !script->source()->IsUndefined()) { 215 int len = String::cast(script->source())->length(); 216 Counters::total_old_codegen_source_size.Increment(len); 217 } 218 MakeCodePrologue(info); 219 // Generate code. 220 const int kInitialBufferSize = 4 * KB; 221 MacroAssembler masm(NULL, kInitialBufferSize); 222 CodeGenerator cgen(&masm); 223 CodeGeneratorScope scope(&cgen); 224 cgen.Generate(info); 225 if (cgen.HasStackOverflow()) { 226 ASSERT(!Top::has_pending_exception()); 227 return Handle<Code>::null(); 228 } 229 230 InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP; 231 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop); 232 return MakeCodeEpilogue(cgen.masm(), flags, info); 233} 234 235 236#ifdef ENABLE_LOGGING_AND_PROFILING 237 238bool CodeGenerator::ShouldGenerateLog(Expression* type) { 239 ASSERT(type != NULL); 240 if (!Logger::is_logging() && !CpuProfiler::is_profiling()) return false; 241 Handle<String> name = Handle<String>::cast(type->AsLiteral()->handle()); 242 if (FLAG_log_regexp) { 243 static Vector<const char> kRegexp = CStrVector("regexp"); 244 if (name->IsEqualTo(kRegexp)) 245 return true; 246 } 247 return false; 248} 249 250#endif 251 252 253Handle<Code> CodeGenerator::ComputeCallInitialize( 254 int argc, 255 InLoopFlag in_loop) { 256 if (in_loop == IN_LOOP) { 257 // Force the creation of the corresponding stub outside loops, 258 // because it may be used when clearing the ICs later - it is 259 // possible for a series of IC transitions to lose the in-loop 260 // information, and the IC clearing code can't generate a stub 261 // that it needs so we need to ensure it is generated already. 262 ComputeCallInitialize(argc, NOT_IN_LOOP); 263 } 264 CALL_HEAP_FUNCTION( 265 StubCache::ComputeCallInitialize(argc, in_loop, Code::CALL_IC), 266 Code); 267} 268 269 270Handle<Code> CodeGenerator::ComputeKeyedCallInitialize( 271 int argc, 272 InLoopFlag in_loop) { 273 if (in_loop == IN_LOOP) { 274 // Force the creation of the corresponding stub outside loops, 275 // because it may be used when clearing the ICs later - it is 276 // possible for a series of IC transitions to lose the in-loop 277 // information, and the IC clearing code can't generate a stub 278 // that it needs so we need to ensure it is generated already. 279 ComputeKeyedCallInitialize(argc, NOT_IN_LOOP); 280 } 281 CALL_HEAP_FUNCTION( 282 StubCache::ComputeCallInitialize(argc, in_loop, Code::KEYED_CALL_IC), 283 Code); 284} 285 286void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) { 287 int length = declarations->length(); 288 int globals = 0; 289 for (int i = 0; i < length; i++) { 290 Declaration* node = declarations->at(i); 291 Variable* var = node->proxy()->var(); 292 Slot* slot = var->slot(); 293 294 // If it was not possible to allocate the variable at compile 295 // time, we need to "declare" it at runtime to make sure it 296 // actually exists in the local context. 297 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) { 298 VisitDeclaration(node); 299 } else { 300 // Count global variables and functions for later processing 301 globals++; 302 } 303 } 304 305 // Return in case of no declared global functions or variables. 306 if (globals == 0) return; 307 308 // Compute array of global variable and function declarations. 309 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED); 310 for (int j = 0, i = 0; i < length; i++) { 311 Declaration* node = declarations->at(i); 312 Variable* var = node->proxy()->var(); 313 Slot* slot = var->slot(); 314 315 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) { 316 // Skip - already processed. 317 } else { 318 array->set(j++, *(var->name())); 319 if (node->fun() == NULL) { 320 if (var->mode() == Variable::CONST) { 321 // In case this is const property use the hole. 322 array->set_the_hole(j++); 323 } else { 324 array->set_undefined(j++); 325 } 326 } else { 327 Handle<SharedFunctionInfo> function = 328 Compiler::BuildFunctionInfo(node->fun(), script(), this); 329 // Check for stack-overflow exception. 330 if (HasStackOverflow()) return; 331 array->set(j++, *function); 332 } 333 } 334 } 335 336 // Invoke the platform-dependent code generator to do the actual 337 // declaration the global variables and functions. 338 DeclareGlobals(array); 339} 340 341 342void CodeGenerator::VisitIncrementOperation(IncrementOperation* expr) { 343 UNREACHABLE(); 344} 345 346 347// List of special runtime calls which are generated inline. For some of these 348// functions the code will be generated inline, and for others a call to a code 349// stub will be inlined. 350 351#define INLINE_RUNTIME_ENTRY(Name, argc, ressize) \ 352 {&CodeGenerator::Generate##Name, "_" #Name, argc}, \ 353 354CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = { 355 INLINE_RUNTIME_FUNCTION_LIST(INLINE_RUNTIME_ENTRY) 356}; 357 358#undef INLINE_RUNTIME_ENTRY 359 360CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT( 361 Handle<String> name) { 362 const int entries_count = 363 sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT); 364 for (int i = 0; i < entries_count; i++) { 365 InlineRuntimeLUT* entry = &kInlineRuntimeLUT[i]; 366 if (name->IsEqualTo(CStrVector(entry->name))) { 367 return entry; 368 } 369 } 370 return NULL; 371} 372 373 374bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) { 375 ZoneList<Expression*>* args = node->arguments(); 376 Handle<String> name = node->name(); 377 if (name->length() > 0 && name->Get(0) == '_') { 378 InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name); 379 if (entry != NULL) { 380 ((*this).*(entry->method))(args); 381 return true; 382 } 383 } 384 return false; 385} 386 387 388int CodeGenerator::InlineRuntimeCallArgumentsCount(Handle<String> name) { 389 CodeGenerator::InlineRuntimeLUT* f = 390 CodeGenerator::FindInlineRuntimeLUT(name); 391 if (f != NULL) return f->nargs; 392 return -1; 393} 394 395 396// Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a 397// known result for the test expression, with no side effects. 398CodeGenerator::ConditionAnalysis CodeGenerator::AnalyzeCondition( 399 Expression* cond) { 400 if (cond == NULL) return ALWAYS_TRUE; 401 402 Literal* lit = cond->AsLiteral(); 403 if (lit == NULL) return DONT_KNOW; 404 405 if (lit->IsTrue()) { 406 return ALWAYS_TRUE; 407 } else if (lit->IsFalse()) { 408 return ALWAYS_FALSE; 409 } 410 411 return DONT_KNOW; 412} 413 414 415bool CodeGenerator::RecordPositions(MacroAssembler* masm, 416 int pos, 417 bool right_here) { 418 if (pos != RelocInfo::kNoPosition) { 419 masm->RecordStatementPosition(pos); 420 masm->RecordPosition(pos); 421 if (right_here) { 422 return masm->WriteRecordedPositions(); 423 } 424 } 425 return false; 426} 427 428 429void CodeGenerator::CodeForFunctionPosition(FunctionLiteral* fun) { 430 if (FLAG_debug_info) RecordPositions(masm(), fun->start_position(), false); 431} 432 433 434void CodeGenerator::CodeForReturnPosition(FunctionLiteral* fun) { 435 if (FLAG_debug_info) RecordPositions(masm(), fun->end_position() - 1, false); 436} 437 438 439void CodeGenerator::CodeForStatementPosition(Statement* stmt) { 440 if (FLAG_debug_info) RecordPositions(masm(), stmt->statement_pos(), false); 441} 442 443 444void CodeGenerator::CodeForDoWhileConditionPosition(DoWhileStatement* stmt) { 445 if (FLAG_debug_info) 446 RecordPositions(masm(), stmt->condition_position(), false); 447} 448 449 450void CodeGenerator::CodeForSourcePosition(int pos) { 451 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) { 452 masm()->RecordPosition(pos); 453 } 454} 455 456 457const char* GenericUnaryOpStub::GetName() { 458 switch (op_) { 459 case Token::SUB: 460 if (negative_zero_ == kStrictNegativeZero) { 461 return overwrite_ == UNARY_OVERWRITE 462 ? "GenericUnaryOpStub_SUB_Overwrite_Strict0" 463 : "GenericUnaryOpStub_SUB_Alloc_Strict0"; 464 } else { 465 return overwrite_ == UNARY_OVERWRITE 466 ? "GenericUnaryOpStub_SUB_Overwrite_Ignore0" 467 : "GenericUnaryOpStub_SUB_Alloc_Ignore0"; 468 } 469 case Token::BIT_NOT: 470 return overwrite_ == UNARY_OVERWRITE 471 ? "GenericUnaryOpStub_BIT_NOT_Overwrite" 472 : "GenericUnaryOpStub_BIT_NOT_Alloc"; 473 default: 474 UNREACHABLE(); 475 return "<unknown>"; 476 } 477} 478 479 480void ArgumentsAccessStub::Generate(MacroAssembler* masm) { 481 switch (type_) { 482 case READ_ELEMENT: GenerateReadElement(masm); break; 483 case NEW_OBJECT: GenerateNewObject(masm); break; 484 } 485} 486 487 488int CEntryStub::MinorKey() { 489 ASSERT(result_size_ == 1 || result_size_ == 2); 490#ifdef _WIN64 491 return result_size_ == 1 ? 0 : 1; 492#else 493 return 0; 494#endif 495} 496 497 498bool ApiGetterEntryStub::GetCustomCache(Code** code_out) { 499 Object* cache = info()->load_stub_cache(); 500 if (cache->IsUndefined()) { 501 return false; 502 } else { 503 *code_out = Code::cast(cache); 504 return true; 505 } 506} 507 508 509void ApiGetterEntryStub::SetCustomCache(Code* value) { 510 info()->set_load_stub_cache(value); 511} 512 513 514} } // namespace v8::internal 515