Home | History | Annotate | Download | only in src
      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