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