Home | History | Annotate | Download | only in src
      1 // Copyright 2012 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 "code-stubs.h"
     32 #include "cpu-profiler.h"
     33 #include "stub-cache.h"
     34 #include "factory.h"
     35 #include "gdb-jit.h"
     36 #include "macro-assembler.h"
     37 
     38 namespace v8 {
     39 namespace internal {
     40 
     41 
     42 CodeStubInterfaceDescriptor::CodeStubInterfaceDescriptor()
     43     : register_param_count_(-1),
     44       stack_parameter_count_(NULL),
     45       hint_stack_parameter_count_(-1),
     46       function_mode_(NOT_JS_FUNCTION_STUB_MODE),
     47       register_params_(NULL),
     48       deoptimization_handler_(NULL),
     49       miss_handler_(IC_Utility(IC::kUnreachable), Isolate::Current()),
     50       has_miss_handler_(false) { }
     51 
     52 
     53 bool CodeStub::FindCodeInCache(Code** code_out, Isolate* isolate) {
     54   UnseededNumberDictionary* stubs = isolate->heap()->code_stubs();
     55   int index = stubs->FindEntry(GetKey());
     56   if (index != UnseededNumberDictionary::kNotFound) {
     57     *code_out = Code::cast(stubs->ValueAt(index));
     58     return true;
     59   }
     60   return false;
     61 }
     62 
     63 
     64 SmartArrayPointer<const char> CodeStub::GetName() {
     65   char buffer[100];
     66   NoAllocationStringAllocator allocator(buffer,
     67                                         static_cast<unsigned>(sizeof(buffer)));
     68   StringStream stream(&allocator);
     69   PrintName(&stream);
     70   return stream.ToCString();
     71 }
     72 
     73 
     74 void CodeStub::RecordCodeGeneration(Code* code, Isolate* isolate) {
     75   SmartArrayPointer<const char> name = GetName();
     76   PROFILE(isolate, CodeCreateEvent(Logger::STUB_TAG, code, *name));
     77   GDBJIT(AddCode(GDBJITInterface::STUB, *name, code));
     78   Counters* counters = isolate->counters();
     79   counters->total_stubs_code_size()->Increment(code->instruction_size());
     80 }
     81 
     82 
     83 Code::Kind CodeStub::GetCodeKind() const {
     84   return Code::STUB;
     85 }
     86 
     87 
     88 Handle<Code> CodeStub::GetCodeCopyFromTemplate(Isolate* isolate) {
     89   Handle<Code> ic = GetCode(isolate);
     90   ic = isolate->factory()->CopyCode(ic);
     91   RecordCodeGeneration(*ic, isolate);
     92   return ic;
     93 }
     94 
     95 
     96 Handle<Code> PlatformCodeStub::GenerateCode() {
     97   Isolate* isolate = Isolate::Current();
     98   Factory* factory = isolate->factory();
     99 
    100   // Generate the new code.
    101   MacroAssembler masm(isolate, NULL, 256);
    102 
    103   {
    104     // Update the static counter each time a new code stub is generated.
    105     isolate->counters()->code_stubs()->Increment();
    106 
    107     // Nested stubs are not allowed for leaves.
    108     AllowStubCallsScope allow_scope(&masm, false);
    109 
    110     // Generate the code for the stub.
    111     masm.set_generating_stub(true);
    112     NoCurrentFrameScope scope(&masm);
    113     Generate(&masm);
    114   }
    115 
    116   // Create the code object.
    117   CodeDesc desc;
    118   masm.GetCode(&desc);
    119 
    120   // Copy the generated code into a heap object.
    121   Code::Flags flags = Code::ComputeFlags(
    122       GetCodeKind(),
    123       GetICState(),
    124       GetExtraICState(),
    125       GetStubType(),
    126       GetStubFlags());
    127   Handle<Code> new_object = factory->NewCode(
    128       desc, flags, masm.CodeObject(), NeedsImmovableCode());
    129   return new_object;
    130 }
    131 
    132 
    133 Handle<Code> CodeStub::GetCode(Isolate* isolate) {
    134   Factory* factory = isolate->factory();
    135   Heap* heap = isolate->heap();
    136   Code* code;
    137   if (UseSpecialCache()
    138       ? FindCodeInSpecialCache(&code, isolate)
    139       : FindCodeInCache(&code, isolate)) {
    140     ASSERT(IsPregenerated() == code->is_pregenerated());
    141     return Handle<Code>(code);
    142   }
    143 
    144   {
    145     HandleScope scope(isolate);
    146 
    147     Handle<Code> new_object = GenerateCode();
    148     new_object->set_major_key(MajorKey());
    149     FinishCode(new_object);
    150     RecordCodeGeneration(*new_object, isolate);
    151 
    152 #ifdef ENABLE_DISASSEMBLER
    153     if (FLAG_print_code_stubs) {
    154       new_object->Disassemble(*GetName());
    155       PrintF("\n");
    156     }
    157 #endif
    158 
    159     if (UseSpecialCache()) {
    160       AddToSpecialCache(new_object);
    161     } else {
    162       // Update the dictionary and the root in Heap.
    163       Handle<UnseededNumberDictionary> dict =
    164           factory->DictionaryAtNumberPut(
    165               Handle<UnseededNumberDictionary>(heap->code_stubs()),
    166               GetKey(),
    167               new_object);
    168       heap->public_set_code_stubs(*dict);
    169     }
    170     code = *new_object;
    171   }
    172 
    173   Activate(code);
    174   ASSERT(!NeedsImmovableCode() ||
    175          heap->lo_space()->Contains(code) ||
    176          heap->code_space()->FirstPage()->Contains(code->address()));
    177   return Handle<Code>(code, isolate);
    178 }
    179 
    180 
    181 const char* CodeStub::MajorName(CodeStub::Major major_key,
    182                                 bool allow_unknown_keys) {
    183   switch (major_key) {
    184 #define DEF_CASE(name) case name: return #name "Stub";
    185     CODE_STUB_LIST(DEF_CASE)
    186 #undef DEF_CASE
    187     default:
    188       if (!allow_unknown_keys) {
    189         UNREACHABLE();
    190       }
    191       return NULL;
    192   }
    193 }
    194 
    195 
    196 void CodeStub::PrintBaseName(StringStream* stream) {
    197   stream->Add("%s", MajorName(MajorKey(), false));
    198 }
    199 
    200 
    201 void CodeStub::PrintName(StringStream* stream) {
    202   PrintBaseName(stream);
    203   PrintState(stream);
    204 }
    205 
    206 
    207 void BinaryOpStub::Generate(MacroAssembler* masm) {
    208   // Explicitly allow generation of nested stubs. It is safe here because
    209   // generation code does not use any raw pointers.
    210   AllowStubCallsScope allow_stub_calls(masm, true);
    211 
    212   BinaryOpIC::TypeInfo operands_type = Max(left_type_, right_type_);
    213   if (left_type_ == BinaryOpIC::ODDBALL && right_type_ == BinaryOpIC::ODDBALL) {
    214     // The OddballStub handles a number and an oddball, not two oddballs.
    215     operands_type = BinaryOpIC::GENERIC;
    216   }
    217   switch (operands_type) {
    218     case BinaryOpIC::UNINITIALIZED:
    219       GenerateTypeTransition(masm);
    220       break;
    221     case BinaryOpIC::SMI:
    222       GenerateSmiStub(masm);
    223       break;
    224     case BinaryOpIC::INT32:
    225       GenerateInt32Stub(masm);
    226       break;
    227     case BinaryOpIC::NUMBER:
    228       GenerateNumberStub(masm);
    229       break;
    230     case BinaryOpIC::ODDBALL:
    231       GenerateOddballStub(masm);
    232       break;
    233     case BinaryOpIC::STRING:
    234       GenerateStringStub(masm);
    235       break;
    236     case BinaryOpIC::GENERIC:
    237       GenerateGeneric(masm);
    238       break;
    239     default:
    240       UNREACHABLE();
    241   }
    242 }
    243 
    244 
    245 #define __ ACCESS_MASM(masm)
    246 
    247 
    248 void BinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
    249   switch (op_) {
    250     case Token::ADD:
    251       __ InvokeBuiltin(Builtins::ADD, CALL_FUNCTION);
    252       break;
    253     case Token::SUB:
    254       __ InvokeBuiltin(Builtins::SUB, CALL_FUNCTION);
    255       break;
    256     case Token::MUL:
    257       __ InvokeBuiltin(Builtins::MUL, CALL_FUNCTION);
    258       break;
    259     case Token::DIV:
    260       __ InvokeBuiltin(Builtins::DIV, CALL_FUNCTION);
    261       break;
    262     case Token::MOD:
    263       __ InvokeBuiltin(Builtins::MOD, CALL_FUNCTION);
    264       break;
    265     case Token::BIT_OR:
    266       __ InvokeBuiltin(Builtins::BIT_OR, CALL_FUNCTION);
    267       break;
    268     case Token::BIT_AND:
    269       __ InvokeBuiltin(Builtins::BIT_AND, CALL_FUNCTION);
    270       break;
    271     case Token::BIT_XOR:
    272       __ InvokeBuiltin(Builtins::BIT_XOR, CALL_FUNCTION);
    273       break;
    274     case Token::SAR:
    275       __ InvokeBuiltin(Builtins::SAR, CALL_FUNCTION);
    276       break;
    277     case Token::SHR:
    278       __ InvokeBuiltin(Builtins::SHR, CALL_FUNCTION);
    279       break;
    280     case Token::SHL:
    281       __ InvokeBuiltin(Builtins::SHL, CALL_FUNCTION);
    282       break;
    283     default:
    284       UNREACHABLE();
    285   }
    286 }
    287 
    288 
    289 #undef __
    290 
    291 
    292 void BinaryOpStub::PrintName(StringStream* stream) {
    293   const char* op_name = Token::Name(op_);
    294   const char* overwrite_name;
    295   switch (mode_) {
    296     case NO_OVERWRITE: overwrite_name = "Alloc"; break;
    297     case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break;
    298     case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break;
    299     default: overwrite_name = "UnknownOverwrite"; break;
    300   }
    301   stream->Add("BinaryOpStub_%s_%s_%s+%s",
    302               op_name,
    303               overwrite_name,
    304               BinaryOpIC::GetName(left_type_),
    305               BinaryOpIC::GetName(right_type_));
    306 }
    307 
    308 
    309 void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
    310   ASSERT(left_type_ == BinaryOpIC::STRING || right_type_ == BinaryOpIC::STRING);
    311   ASSERT(op_ == Token::ADD);
    312   if (left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING) {
    313     GenerateBothStringStub(masm);
    314     return;
    315   }
    316   // Try to add arguments as strings, otherwise, transition to the generic
    317   // BinaryOpIC type.
    318   GenerateAddStrings(masm);
    319   GenerateTypeTransition(masm);
    320 }
    321 
    322 
    323 InlineCacheState ICCompareStub::GetICState() {
    324   CompareIC::State state = Max(left_, right_);
    325   switch (state) {
    326     case CompareIC::UNINITIALIZED:
    327       return ::v8::internal::UNINITIALIZED;
    328     case CompareIC::SMI:
    329     case CompareIC::NUMBER:
    330     case CompareIC::INTERNALIZED_STRING:
    331     case CompareIC::STRING:
    332     case CompareIC::UNIQUE_NAME:
    333     case CompareIC::OBJECT:
    334     case CompareIC::KNOWN_OBJECT:
    335       return MONOMORPHIC;
    336     case CompareIC::GENERIC:
    337       return ::v8::internal::GENERIC;
    338   }
    339   UNREACHABLE();
    340   return ::v8::internal::UNINITIALIZED;
    341 }
    342 
    343 
    344 void ICCompareStub::AddToSpecialCache(Handle<Code> new_object) {
    345   ASSERT(*known_map_ != NULL);
    346   Isolate* isolate = new_object->GetIsolate();
    347   Factory* factory = isolate->factory();
    348   return Map::UpdateCodeCache(known_map_,
    349                               strict() ?
    350                                   factory->strict_compare_ic_string() :
    351                                   factory->compare_ic_string(),
    352                               new_object);
    353 }
    354 
    355 
    356 bool ICCompareStub::FindCodeInSpecialCache(Code** code_out, Isolate* isolate) {
    357   Factory* factory = isolate->factory();
    358   Code::Flags flags = Code::ComputeFlags(
    359       GetCodeKind(),
    360       UNINITIALIZED);
    361   ASSERT(op_ == Token::EQ || op_ == Token::EQ_STRICT);
    362   Handle<Object> probe(
    363       known_map_->FindInCodeCache(
    364         strict() ?
    365             *factory->strict_compare_ic_string() :
    366             *factory->compare_ic_string(),
    367         flags),
    368       isolate);
    369   if (probe->IsCode()) {
    370     *code_out = Code::cast(*probe);
    371 #ifdef DEBUG
    372     Token::Value cached_op;
    373     ICCompareStub::DecodeMinorKey((*code_out)->stub_info(), NULL, NULL, NULL,
    374                                   &cached_op);
    375     ASSERT(op_ == cached_op);
    376 #endif
    377     return true;
    378   }
    379   return false;
    380 }
    381 
    382 
    383 int ICCompareStub::MinorKey() {
    384   return OpField::encode(op_ - Token::EQ) |
    385          LeftStateField::encode(left_) |
    386          RightStateField::encode(right_) |
    387          HandlerStateField::encode(state_);
    388 }
    389 
    390 
    391 void ICCompareStub::DecodeMinorKey(int minor_key,
    392                                    CompareIC::State* left_state,
    393                                    CompareIC::State* right_state,
    394                                    CompareIC::State* handler_state,
    395                                    Token::Value* op) {
    396   if (left_state) {
    397     *left_state =
    398         static_cast<CompareIC::State>(LeftStateField::decode(minor_key));
    399   }
    400   if (right_state) {
    401     *right_state =
    402         static_cast<CompareIC::State>(RightStateField::decode(minor_key));
    403   }
    404   if (handler_state) {
    405     *handler_state =
    406         static_cast<CompareIC::State>(HandlerStateField::decode(minor_key));
    407   }
    408   if (op) {
    409     *op = static_cast<Token::Value>(OpField::decode(minor_key) + Token::EQ);
    410   }
    411 }
    412 
    413 
    414 void ICCompareStub::Generate(MacroAssembler* masm) {
    415   switch (state_) {
    416     case CompareIC::UNINITIALIZED:
    417       GenerateMiss(masm);
    418       break;
    419     case CompareIC::SMI:
    420       GenerateSmis(masm);
    421       break;
    422     case CompareIC::NUMBER:
    423       GenerateNumbers(masm);
    424       break;
    425     case CompareIC::STRING:
    426       GenerateStrings(masm);
    427       break;
    428     case CompareIC::INTERNALIZED_STRING:
    429       GenerateInternalizedStrings(masm);
    430       break;
    431     case CompareIC::UNIQUE_NAME:
    432       GenerateUniqueNames(masm);
    433       break;
    434     case CompareIC::OBJECT:
    435       GenerateObjects(masm);
    436       break;
    437     case CompareIC::KNOWN_OBJECT:
    438       ASSERT(*known_map_ != NULL);
    439       GenerateKnownObjects(masm);
    440       break;
    441     case CompareIC::GENERIC:
    442       GenerateGeneric(masm);
    443       break;
    444   }
    445 }
    446 
    447 
    448 void CompareNilICStub::UpdateStatus(Handle<Object> object) {
    449   ASSERT(!state_.Contains(GENERIC));
    450   State old_state(state_);
    451   if (object->IsNull()) {
    452     state_.Add(NULL_TYPE);
    453   } else if (object->IsUndefined()) {
    454     state_.Add(UNDEFINED);
    455   } else if (object->IsUndetectableObject() ||
    456              object->IsOddball() ||
    457              !object->IsHeapObject()) {
    458     state_.RemoveAll();
    459     state_.Add(GENERIC);
    460   } else if (IsMonomorphic()) {
    461     state_.RemoveAll();
    462     state_.Add(GENERIC);
    463   } else {
    464     state_.Add(MONOMORPHIC_MAP);
    465   }
    466   TraceTransition(old_state, state_);
    467 }
    468 
    469 
    470 template<class StateType>
    471 void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
    472   // Note: Although a no-op transition is semantically OK, it is hinting at a
    473   // bug somewhere in our state transition machinery.
    474   ASSERT(from != to);
    475   #ifdef DEBUG
    476   if (!FLAG_trace_ic) return;
    477   char buffer[100];
    478   NoAllocationStringAllocator allocator(buffer,
    479                                         static_cast<unsigned>(sizeof(buffer)));
    480   StringStream stream(&allocator);
    481   stream.Add("[");
    482   PrintBaseName(&stream);
    483   stream.Add(": ");
    484   from.Print(&stream);
    485   stream.Add("=>");
    486   to.Print(&stream);
    487   stream.Add("]\n");
    488   stream.OutputToStdOut();
    489   #endif
    490 }
    491 
    492 
    493 void CompareNilICStub::PrintBaseName(StringStream* stream) {
    494   CodeStub::PrintBaseName(stream);
    495   stream->Add((nil_value_ == kNullValue) ? "(NullValue)":
    496                                            "(UndefinedValue)");
    497 }
    498 
    499 
    500 void CompareNilICStub::PrintState(StringStream* stream) {
    501   state_.Print(stream);
    502 }
    503 
    504 
    505 void CompareNilICStub::State::Print(StringStream* stream) const {
    506   stream->Add("(");
    507   SimpleListPrinter printer(stream);
    508   if (IsEmpty()) printer.Add("None");
    509   if (Contains(UNDEFINED)) printer.Add("Undefined");
    510   if (Contains(NULL_TYPE)) printer.Add("Null");
    511   if (Contains(MONOMORPHIC_MAP)) printer.Add("MonomorphicMap");
    512   if (Contains(GENERIC)) printer.Add("Generic");
    513   stream->Add(")");
    514 }
    515 
    516 
    517 Handle<Type> CompareNilICStub::GetType(
    518     Isolate* isolate,
    519     Handle<Map> map) {
    520   if (state_.Contains(CompareNilICStub::GENERIC)) {
    521     return handle(Type::Any(), isolate);
    522   }
    523 
    524   Handle<Type> result(Type::None(), isolate);
    525   if (state_.Contains(CompareNilICStub::UNDEFINED)) {
    526     result = handle(Type::Union(result, handle(Type::Undefined(), isolate)),
    527                     isolate);
    528   }
    529   if (state_.Contains(CompareNilICStub::NULL_TYPE)) {
    530     result = handle(Type::Union(result, handle(Type::Null(), isolate)),
    531                     isolate);
    532   }
    533   if (state_.Contains(CompareNilICStub::MONOMORPHIC_MAP)) {
    534     Type* type = map.is_null() ? Type::Detectable() : Type::Class(map);
    535     result = handle(Type::Union(result, handle(type, isolate)), isolate);
    536   }
    537 
    538   return result;
    539 }
    540 
    541 
    542 Handle<Type> CompareNilICStub::GetInputType(
    543     Isolate* isolate,
    544     Handle<Map> map) {
    545   Handle<Type> output_type = GetType(isolate, map);
    546   Handle<Type> nil_type = handle(nil_value_ == kNullValue
    547       ? Type::Null() : Type::Undefined(), isolate);
    548   return handle(Type::Union(output_type, nil_type), isolate);
    549 }
    550 
    551 
    552 void InstanceofStub::PrintName(StringStream* stream) {
    553   const char* args = "";
    554   if (HasArgsInRegisters()) {
    555     args = "_REGS";
    556   }
    557 
    558   const char* inline_check = "";
    559   if (HasCallSiteInlineCheck()) {
    560     inline_check = "_INLINE";
    561   }
    562 
    563   const char* return_true_false_object = "";
    564   if (ReturnTrueFalseObject()) {
    565     return_true_false_object = "_TRUEFALSE";
    566   }
    567 
    568   stream->Add("InstanceofStub%s%s%s",
    569               args,
    570               inline_check,
    571               return_true_false_object);
    572 }
    573 
    574 
    575 void JSEntryStub::FinishCode(Handle<Code> code) {
    576   Handle<FixedArray> handler_table =
    577       code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
    578   handler_table->set(0, Smi::FromInt(handler_offset_));
    579   code->set_handler_table(*handler_table);
    580 }
    581 
    582 
    583 void KeyedLoadDictionaryElementStub::Generate(MacroAssembler* masm) {
    584   KeyedLoadStubCompiler::GenerateLoadDictionaryElement(masm);
    585 }
    586 
    587 
    588 void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
    589   CreateAllocationSiteStub stub;
    590   stub.GetCode(isolate)->set_is_pregenerated(true);
    591 }
    592 
    593 
    594 void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
    595   switch (elements_kind_) {
    596     case FAST_ELEMENTS:
    597     case FAST_HOLEY_ELEMENTS:
    598     case FAST_SMI_ELEMENTS:
    599     case FAST_HOLEY_SMI_ELEMENTS: {
    600       KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
    601                                                        is_js_array_,
    602                                                        elements_kind_,
    603                                                        store_mode_);
    604     }
    605       break;
    606     case FAST_DOUBLE_ELEMENTS:
    607     case FAST_HOLEY_DOUBLE_ELEMENTS:
    608       KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
    609                                                              is_js_array_,
    610                                                              store_mode_);
    611       break;
    612     case EXTERNAL_BYTE_ELEMENTS:
    613     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
    614     case EXTERNAL_SHORT_ELEMENTS:
    615     case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
    616     case EXTERNAL_INT_ELEMENTS:
    617     case EXTERNAL_UNSIGNED_INT_ELEMENTS:
    618     case EXTERNAL_FLOAT_ELEMENTS:
    619     case EXTERNAL_DOUBLE_ELEMENTS:
    620     case EXTERNAL_PIXEL_ELEMENTS:
    621       KeyedStoreStubCompiler::GenerateStoreExternalArray(masm, elements_kind_);
    622       break;
    623     case DICTIONARY_ELEMENTS:
    624       KeyedStoreStubCompiler::GenerateStoreDictionaryElement(masm);
    625       break;
    626     case NON_STRICT_ARGUMENTS_ELEMENTS:
    627       UNREACHABLE();
    628       break;
    629   }
    630 }
    631 
    632 
    633 void ArgumentsAccessStub::PrintName(StringStream* stream) {
    634   stream->Add("ArgumentsAccessStub_");
    635   switch (type_) {
    636     case READ_ELEMENT: stream->Add("ReadElement"); break;
    637     case NEW_NON_STRICT_FAST: stream->Add("NewNonStrictFast"); break;
    638     case NEW_NON_STRICT_SLOW: stream->Add("NewNonStrictSlow"); break;
    639     case NEW_STRICT: stream->Add("NewStrict"); break;
    640   }
    641 }
    642 
    643 
    644 void CallFunctionStub::PrintName(StringStream* stream) {
    645   stream->Add("CallFunctionStub_Args%d", argc_);
    646   if (ReceiverMightBeImplicit()) stream->Add("_Implicit");
    647   if (RecordCallTarget()) stream->Add("_Recording");
    648 }
    649 
    650 
    651 void CallConstructStub::PrintName(StringStream* stream) {
    652   stream->Add("CallConstructStub");
    653   if (RecordCallTarget()) stream->Add("_Recording");
    654 }
    655 
    656 
    657 bool ToBooleanStub::UpdateStatus(Handle<Object> object) {
    658   Types old_types(types_);
    659   bool to_boolean_value = types_.UpdateStatus(object);
    660   TraceTransition(old_types, types_);
    661   return to_boolean_value;
    662 }
    663 
    664 
    665 void ToBooleanStub::PrintState(StringStream* stream) {
    666   types_.Print(stream);
    667 }
    668 
    669 
    670 void ToBooleanStub::Types::Print(StringStream* stream) const {
    671   stream->Add("(");
    672   SimpleListPrinter printer(stream);
    673   if (IsEmpty()) printer.Add("None");
    674   if (Contains(UNDEFINED)) printer.Add("Undefined");
    675   if (Contains(BOOLEAN)) printer.Add("Bool");
    676   if (Contains(NULL_TYPE)) printer.Add("Null");
    677   if (Contains(SMI)) printer.Add("Smi");
    678   if (Contains(SPEC_OBJECT)) printer.Add("SpecObject");
    679   if (Contains(STRING)) printer.Add("String");
    680   if (Contains(SYMBOL)) printer.Add("Symbol");
    681   if (Contains(HEAP_NUMBER)) printer.Add("HeapNumber");
    682   stream->Add(")");
    683 }
    684 
    685 
    686 bool ToBooleanStub::Types::UpdateStatus(Handle<Object> object) {
    687   if (object->IsUndefined()) {
    688     Add(UNDEFINED);
    689     return false;
    690   } else if (object->IsBoolean()) {
    691     Add(BOOLEAN);
    692     return object->IsTrue();
    693   } else if (object->IsNull()) {
    694     Add(NULL_TYPE);
    695     return false;
    696   } else if (object->IsSmi()) {
    697     Add(SMI);
    698     return Smi::cast(*object)->value() != 0;
    699   } else if (object->IsSpecObject()) {
    700     Add(SPEC_OBJECT);
    701     return !object->IsUndetectableObject();
    702   } else if (object->IsString()) {
    703     Add(STRING);
    704     return !object->IsUndetectableObject() &&
    705         String::cast(*object)->length() != 0;
    706   } else if (object->IsSymbol()) {
    707     Add(SYMBOL);
    708     return true;
    709   } else if (object->IsHeapNumber()) {
    710     ASSERT(!object->IsUndetectableObject());
    711     Add(HEAP_NUMBER);
    712     double value = HeapNumber::cast(*object)->value();
    713     return value != 0 && !std::isnan(value);
    714   } else {
    715     // We should never see an internal object at runtime here!
    716     UNREACHABLE();
    717     return true;
    718   }
    719 }
    720 
    721 
    722 bool ToBooleanStub::Types::NeedsMap() const {
    723   return Contains(ToBooleanStub::SPEC_OBJECT)
    724       || Contains(ToBooleanStub::STRING)
    725       || Contains(ToBooleanStub::SYMBOL)
    726       || Contains(ToBooleanStub::HEAP_NUMBER);
    727 }
    728 
    729 
    730 bool ToBooleanStub::Types::CanBeUndetectable() const {
    731   return Contains(ToBooleanStub::SPEC_OBJECT)
    732       || Contains(ToBooleanStub::STRING);
    733 }
    734 
    735 
    736 void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
    737   StubFailureTrampolineStub stub1(NOT_JS_FUNCTION_STUB_MODE);
    738   StubFailureTrampolineStub stub2(JS_FUNCTION_STUB_MODE);
    739   stub1.GetCode(isolate)->set_is_pregenerated(true);
    740   stub2.GetCode(isolate)->set_is_pregenerated(true);
    741 }
    742 
    743 
    744 void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
    745                                                intptr_t stack_pointer) {
    746   FunctionEntryHook entry_hook = Isolate::Current()->function_entry_hook();
    747   ASSERT(entry_hook != NULL);
    748   entry_hook(function, stack_pointer);
    749 }
    750 
    751 
    752 static void InstallDescriptor(Isolate* isolate, HydrogenCodeStub* stub) {
    753   int major_key = stub->MajorKey();
    754   CodeStubInterfaceDescriptor* descriptor =
    755       isolate->code_stub_interface_descriptor(major_key);
    756   if (!descriptor->initialized()) {
    757     stub->InitializeInterfaceDescriptor(isolate, descriptor);
    758   }
    759 }
    760 
    761 
    762 void ArrayConstructorStubBase::InstallDescriptors(Isolate* isolate) {
    763   ArrayNoArgumentConstructorStub stub1(GetInitialFastElementsKind());
    764   InstallDescriptor(isolate, &stub1);
    765   ArraySingleArgumentConstructorStub stub2(GetInitialFastElementsKind());
    766   InstallDescriptor(isolate, &stub2);
    767   ArrayNArgumentsConstructorStub stub3(GetInitialFastElementsKind());
    768   InstallDescriptor(isolate, &stub3);
    769 }
    770 
    771 
    772 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
    773     : argument_count_(ANY) {
    774   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
    775 }
    776 
    777 
    778 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
    779                                            int argument_count) {
    780   if (argument_count == 0) {
    781     argument_count_ = NONE;
    782   } else if (argument_count == 1) {
    783     argument_count_ = ONE;
    784   } else if (argument_count >= 2) {
    785     argument_count_ = MORE_THAN_ONE;
    786   } else {
    787     UNREACHABLE();
    788   }
    789   ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
    790 }
    791 
    792 
    793 void InternalArrayConstructorStubBase::InstallDescriptors(Isolate* isolate) {
    794   InternalArrayNoArgumentConstructorStub stub1(FAST_ELEMENTS);
    795   InstallDescriptor(isolate, &stub1);
    796   InternalArraySingleArgumentConstructorStub stub2(FAST_ELEMENTS);
    797   InstallDescriptor(isolate, &stub2);
    798   InternalArrayNArgumentsConstructorStub stub3(FAST_ELEMENTS);
    799   InstallDescriptor(isolate, &stub3);
    800 }
    801 
    802 InternalArrayConstructorStub::InternalArrayConstructorStub(
    803     Isolate* isolate) {
    804   InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
    805 }
    806 
    807 
    808 } }  // namespace v8::internal
    809