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 "code-stubs.h"
     31 #include "hydrogen.h"
     32 #include "lithium.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 
     38 static LChunk* OptimizeGraph(HGraph* graph) {
     39   DisallowHeapAllocation no_allocation;
     40   DisallowHandleAllocation no_handles;
     41   DisallowHandleDereference no_deref;
     42 
     43   ASSERT(graph != NULL);
     44   BailoutReason bailout_reason = kNoReason;
     45   if (!graph->Optimize(&bailout_reason)) {
     46     FATAL(GetBailoutReason(bailout_reason));
     47   }
     48   LChunk* chunk = LChunk::NewChunk(graph);
     49   if (chunk == NULL) {
     50     FATAL(GetBailoutReason(graph->info()->bailout_reason()));
     51   }
     52   return chunk;
     53 }
     54 
     55 
     56 class CodeStubGraphBuilderBase : public HGraphBuilder {
     57  public:
     58   CodeStubGraphBuilderBase(Isolate* isolate, HydrogenCodeStub* stub)
     59       : HGraphBuilder(&info_),
     60         arguments_length_(NULL),
     61         info_(stub, isolate),
     62         context_(NULL) {
     63     descriptor_ = stub->GetInterfaceDescriptor(isolate);
     64     parameters_.Reset(new HParameter*[descriptor_->register_param_count_]);
     65   }
     66   virtual bool BuildGraph();
     67 
     68  protected:
     69   virtual HValue* BuildCodeStub() = 0;
     70   HParameter* GetParameter(int parameter) {
     71     ASSERT(parameter < descriptor_->register_param_count_);
     72     return parameters_[parameter];
     73   }
     74   HValue* GetArgumentsLength() {
     75     // This is initialized in BuildGraph()
     76     ASSERT(arguments_length_ != NULL);
     77     return arguments_length_;
     78   }
     79   CompilationInfo* info() { return &info_; }
     80   HydrogenCodeStub* stub() { return info_.code_stub(); }
     81   HContext* context() { return context_; }
     82   Isolate* isolate() { return info_.isolate(); }
     83 
     84   class ArrayContextChecker {
     85    public:
     86     ArrayContextChecker(HGraphBuilder* builder, HValue* constructor,
     87                         HValue* array_function)
     88         : checker_(builder) {
     89       checker_.If<HCompareObjectEqAndBranch, HValue*>(constructor,
     90                                                       array_function);
     91       checker_.Then();
     92     }
     93 
     94     ~ArrayContextChecker() {
     95       checker_.ElseDeopt("Array constructor called from different context");
     96       checker_.End();
     97     }
     98    private:
     99     IfBuilder checker_;
    100   };
    101 
    102   enum ArgumentClass {
    103     NONE,
    104     SINGLE,
    105     MULTIPLE
    106   };
    107 
    108   HValue* BuildArrayConstructor(ElementsKind kind,
    109                                 ContextCheckMode context_mode,
    110                                 AllocationSiteOverrideMode override_mode,
    111                                 ArgumentClass argument_class);
    112   HValue* BuildInternalArrayConstructor(ElementsKind kind,
    113                                         ArgumentClass argument_class);
    114 
    115  private:
    116   HValue* BuildArraySingleArgumentConstructor(JSArrayBuilder* builder);
    117   HValue* BuildArrayNArgumentsConstructor(JSArrayBuilder* builder,
    118                                           ElementsKind kind);
    119 
    120   SmartArrayPointer<HParameter*> parameters_;
    121   HValue* arguments_length_;
    122   CompilationInfoWithZone info_;
    123   CodeStubInterfaceDescriptor* descriptor_;
    124   HContext* context_;
    125 };
    126 
    127 
    128 bool CodeStubGraphBuilderBase::BuildGraph() {
    129   // Update the static counter each time a new code stub is generated.
    130   isolate()->counters()->code_stubs()->Increment();
    131 
    132   if (FLAG_trace_hydrogen_stubs) {
    133     const char* name = CodeStub::MajorName(stub()->MajorKey(), false);
    134     PrintF("-----------------------------------------------------------\n");
    135     PrintF("Compiling stub %s using hydrogen\n", name);
    136     isolate()->GetHTracer()->TraceCompilation(&info_);
    137   }
    138 
    139   int param_count = descriptor_->register_param_count_;
    140   HEnvironment* start_environment = graph()->start_environment();
    141   HBasicBlock* next_block = CreateBasicBlock(start_environment);
    142   current_block()->Goto(next_block);
    143   next_block->SetJoinId(BailoutId::StubEntry());
    144   set_current_block(next_block);
    145 
    146   HConstant* undefined_constant =
    147       Add<HConstant>(isolate()->factory()->undefined_value());
    148   graph()->set_undefined_constant(undefined_constant);
    149 
    150   for (int i = 0; i < param_count; ++i) {
    151     HParameter* param =
    152         Add<HParameter>(i, HParameter::REGISTER_PARAMETER);
    153     start_environment->Bind(i, param);
    154     parameters_[i] = param;
    155   }
    156 
    157   HInstruction* stack_parameter_count;
    158   if (descriptor_->stack_parameter_count_ != NULL) {
    159     ASSERT(descriptor_->environment_length() == (param_count + 1));
    160     stack_parameter_count = New<HParameter>(param_count,
    161                                             HParameter::REGISTER_PARAMETER,
    162                                             Representation::Integer32());
    163     stack_parameter_count->set_type(HType::Smi());
    164     // It's essential to bind this value to the environment in case of deopt.
    165     AddInstruction(stack_parameter_count);
    166     start_environment->Bind(param_count, stack_parameter_count);
    167     arguments_length_ = stack_parameter_count;
    168   } else {
    169     ASSERT(descriptor_->environment_length() == param_count);
    170     stack_parameter_count = graph()->GetConstantMinus1();
    171     arguments_length_ = graph()->GetConstant0();
    172   }
    173 
    174   context_ = New<HContext>();
    175   AddInstruction(context_);
    176   start_environment->BindContext(context_);
    177 
    178   Add<HSimulate>(BailoutId::StubEntry());
    179 
    180   NoObservableSideEffectsScope no_effects(this);
    181 
    182   HValue* return_value = BuildCodeStub();
    183 
    184   // We might have extra expressions to pop from the stack in addition to the
    185   // arguments above.
    186   HInstruction* stack_pop_count = stack_parameter_count;
    187   if (descriptor_->function_mode_ == JS_FUNCTION_STUB_MODE) {
    188     if (!stack_parameter_count->IsConstant() &&
    189         descriptor_->hint_stack_parameter_count_ < 0) {
    190       HInstruction* amount = graph()->GetConstant1();
    191       stack_pop_count = Add<HAdd>(stack_parameter_count, amount);
    192       stack_pop_count->ChangeRepresentation(Representation::Integer32());
    193       stack_pop_count->ClearFlag(HValue::kCanOverflow);
    194     } else {
    195       int count = descriptor_->hint_stack_parameter_count_;
    196       stack_pop_count = Add<HConstant>(count);
    197     }
    198   }
    199 
    200   if (current_block() != NULL) {
    201     HReturn* hreturn_instruction = New<HReturn>(return_value,
    202                                                 stack_pop_count);
    203     current_block()->Finish(hreturn_instruction);
    204     set_current_block(NULL);
    205   }
    206   return true;
    207 }
    208 
    209 
    210 template <class Stub>
    211 class CodeStubGraphBuilder: public CodeStubGraphBuilderBase {
    212  public:
    213   explicit CodeStubGraphBuilder(Stub* stub)
    214       : CodeStubGraphBuilderBase(Isolate::Current(), stub) {}
    215 
    216  protected:
    217   virtual HValue* BuildCodeStub() {
    218     if (casted_stub()->IsUninitialized()) {
    219       return BuildCodeUninitializedStub();
    220     } else {
    221       return BuildCodeInitializedStub();
    222     }
    223   }
    224 
    225   virtual HValue* BuildCodeInitializedStub() {
    226     UNIMPLEMENTED();
    227     return NULL;
    228   }
    229 
    230   virtual HValue* BuildCodeUninitializedStub() {
    231     // Force a deopt that falls back to the runtime.
    232     HValue* undefined = graph()->GetConstantUndefined();
    233     IfBuilder builder(this);
    234     builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined);
    235     builder.Then();
    236     builder.ElseDeopt("Forced deopt to runtime");
    237     return undefined;
    238   }
    239 
    240   Stub* casted_stub() { return static_cast<Stub*>(stub()); }
    241 };
    242 
    243 
    244 Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(Isolate* isolate) {
    245   Factory* factory = isolate->factory();
    246 
    247   // Generate the new code.
    248   MacroAssembler masm(isolate, NULL, 256);
    249 
    250   {
    251     // Update the static counter each time a new code stub is generated.
    252     isolate->counters()->code_stubs()->Increment();
    253 
    254     // Nested stubs are not allowed for leaves.
    255     AllowStubCallsScope allow_scope(&masm, false);
    256 
    257     // Generate the code for the stub.
    258     masm.set_generating_stub(true);
    259     NoCurrentFrameScope scope(&masm);
    260     GenerateLightweightMiss(&masm);
    261   }
    262 
    263   // Create the code object.
    264   CodeDesc desc;
    265   masm.GetCode(&desc);
    266 
    267   // Copy the generated code into a heap object.
    268   Code::Flags flags = Code::ComputeFlags(
    269       GetCodeKind(),
    270       GetICState(),
    271       GetExtraICState(),
    272       GetStubType(),
    273       GetStubFlags());
    274   Handle<Code> new_object = factory->NewCode(
    275       desc, flags, masm.CodeObject(), NeedsImmovableCode());
    276   return new_object;
    277 }
    278 
    279 
    280 template <class Stub>
    281 static Handle<Code> DoGenerateCode(Stub* stub) {
    282   Isolate* isolate = Isolate::Current();
    283   CodeStub::Major  major_key =
    284       static_cast<HydrogenCodeStub*>(stub)->MajorKey();
    285   CodeStubInterfaceDescriptor* descriptor =
    286       isolate->code_stub_interface_descriptor(major_key);
    287   if (descriptor->register_param_count_ < 0) {
    288     stub->InitializeInterfaceDescriptor(isolate, descriptor);
    289   }
    290 
    291   // If we are uninitialized we can use a light-weight stub to enter
    292   // the runtime that is significantly faster than using the standard
    293   // stub-failure deopt mechanism.
    294   if (stub->IsUninitialized() && descriptor->has_miss_handler()) {
    295     ASSERT(descriptor->stack_parameter_count_ == NULL);
    296     return stub->GenerateLightweightMissCode(isolate);
    297   }
    298   CodeStubGraphBuilder<Stub> builder(stub);
    299   LChunk* chunk = OptimizeGraph(builder.CreateGraph());
    300   return chunk->Codegen();
    301 }
    302 
    303 
    304 template <>
    305 HValue* CodeStubGraphBuilder<ToNumberStub>::BuildCodeStub() {
    306   HValue* value = GetParameter(0);
    307 
    308   // Check if the parameter is already a SMI or heap number.
    309   IfBuilder if_number(this);
    310   if_number.If<HIsSmiAndBranch>(value);
    311   if_number.OrIf<HCompareMap>(value, isolate()->factory()->heap_number_map());
    312   if_number.Then();
    313 
    314   // Return the number.
    315   Push(value);
    316 
    317   if_number.Else();
    318 
    319   // Convert the parameter to number using the builtin.
    320   HValue* function = AddLoadJSBuiltin(Builtins::TO_NUMBER);
    321   Add<HPushArgument>(value);
    322   Push(Add<HInvokeFunction>(function, 1));
    323 
    324   if_number.End();
    325 
    326   return Pop();
    327 }
    328 
    329 
    330 Handle<Code> ToNumberStub::GenerateCode() {
    331   return DoGenerateCode(this);
    332 }
    333 
    334 
    335 template <>
    336 HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
    337   Factory* factory = isolate()->factory();
    338   HValue* undefined = graph()->GetConstantUndefined();
    339   AllocationSiteMode alloc_site_mode = casted_stub()->allocation_site_mode();
    340   FastCloneShallowArrayStub::Mode mode = casted_stub()->mode();
    341   int length = casted_stub()->length();
    342 
    343   HInstruction* allocation_site = Add<HLoadKeyed>(GetParameter(0),
    344                                                   GetParameter(1),
    345                                                   static_cast<HValue*>(NULL),
    346                                                   FAST_ELEMENTS);
    347   IfBuilder checker(this);
    348   checker.IfNot<HCompareObjectEqAndBranch, HValue*>(allocation_site,
    349                                                     undefined);
    350   checker.Then();
    351 
    352   HObjectAccess access = HObjectAccess::ForAllocationSiteTransitionInfo();
    353   HInstruction* boilerplate = Add<HLoadNamedField>(allocation_site, access);
    354   if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
    355     HValue* elements = AddLoadElements(boilerplate, NULL);
    356 
    357     IfBuilder if_fixed_cow(this);
    358     if_fixed_cow.If<HCompareMap>(elements, factory->fixed_cow_array_map());
    359     if_fixed_cow.Then();
    360     environment()->Push(BuildCloneShallowArray(boilerplate,
    361                                                allocation_site,
    362                                                alloc_site_mode,
    363                                                FAST_ELEMENTS,
    364                                                0/*copy-on-write*/));
    365     if_fixed_cow.Else();
    366 
    367     IfBuilder if_fixed(this);
    368     if_fixed.If<HCompareMap>(elements, factory->fixed_array_map());
    369     if_fixed.Then();
    370     environment()->Push(BuildCloneShallowArray(boilerplate,
    371                                                allocation_site,
    372                                                alloc_site_mode,
    373                                                FAST_ELEMENTS,
    374                                                length));
    375     if_fixed.Else();
    376     environment()->Push(BuildCloneShallowArray(boilerplate,
    377                                                allocation_site,
    378                                                alloc_site_mode,
    379                                                FAST_DOUBLE_ELEMENTS,
    380                                                length));
    381   } else {
    382     ElementsKind elements_kind = casted_stub()->ComputeElementsKind();
    383     environment()->Push(BuildCloneShallowArray(boilerplate,
    384                                                allocation_site,
    385                                                alloc_site_mode,
    386                                                elements_kind,
    387                                                length));
    388   }
    389 
    390   checker.ElseDeopt("Uninitialized boilerplate literals");
    391   checker.End();
    392 
    393   return environment()->Pop();
    394 }
    395 
    396 
    397 Handle<Code> FastCloneShallowArrayStub::GenerateCode() {
    398   return DoGenerateCode(this);
    399 }
    400 
    401 
    402 template <>
    403 HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
    404   Zone* zone = this->zone();
    405   HValue* undefined = graph()->GetConstantUndefined();
    406 
    407   HInstruction* boilerplate = Add<HLoadKeyed>(GetParameter(0),
    408                                               GetParameter(1),
    409                                               static_cast<HValue*>(NULL),
    410                                               FAST_ELEMENTS);
    411 
    412   IfBuilder checker(this);
    413   checker.IfNot<HCompareObjectEqAndBranch, HValue*>(boilerplate,
    414                                                     undefined);
    415   checker.And();
    416 
    417   int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize;
    418   HValue* boilerplate_size =
    419       AddInstruction(new(zone) HInstanceSize(boilerplate));
    420   HValue* size_in_words = Add<HConstant>(size >> kPointerSizeLog2);
    421   checker.If<HCompareNumericAndBranch>(boilerplate_size,
    422                                        size_in_words, Token::EQ);
    423   checker.Then();
    424 
    425   HValue* size_in_bytes = Add<HConstant>(size);
    426 
    427   HInstruction* object = Add<HAllocate>(size_in_bytes, HType::JSObject(),
    428       isolate()->heap()->GetPretenureMode(), JS_OBJECT_TYPE);
    429 
    430   for (int i = 0; i < size; i += kPointerSize) {
    431     HObjectAccess access = HObjectAccess::ForJSObjectOffset(i);
    432     Add<HStoreNamedField>(object, access,
    433                           Add<HLoadNamedField>(boilerplate, access));
    434   }
    435 
    436   environment()->Push(object);
    437   checker.ElseDeopt("Uninitialized boilerplate in fast clone");
    438   checker.End();
    439 
    440   return environment()->Pop();
    441 }
    442 
    443 
    444 Handle<Code> FastCloneShallowObjectStub::GenerateCode() {
    445   return DoGenerateCode(this);
    446 }
    447 
    448 
    449 template <>
    450 HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
    451   HValue* size = Add<HConstant>(AllocationSite::kSize);
    452   HInstruction* object = Add<HAllocate>(size, HType::JSObject(), TENURED,
    453       JS_OBJECT_TYPE);
    454 
    455   // Store the map
    456   Handle<Map> allocation_site_map(isolate()->heap()->allocation_site_map(),
    457                                   isolate());
    458   AddStoreMapConstant(object, allocation_site_map);
    459 
    460   // Store the payload (smi elements kind)
    461   HValue* initial_elements_kind = Add<HConstant>(GetInitialFastElementsKind());
    462   Add<HStoreNamedField>(object,
    463                         HObjectAccess::ForAllocationSiteTransitionInfo(),
    464                         initial_elements_kind);
    465 
    466   // Link the object to the allocation site list
    467   HValue* site_list = Add<HConstant>(
    468       ExternalReference::allocation_sites_list_address(isolate()));
    469   HValue* site = Add<HLoadNamedField>(site_list,
    470                                       HObjectAccess::ForAllocationSiteList());
    471   HStoreNamedField* store =
    472       Add<HStoreNamedField>(object, HObjectAccess::ForAllocationSiteWeakNext(),
    473                             site);
    474   store->SkipWriteBarrier();
    475   Add<HStoreNamedField>(site_list, HObjectAccess::ForAllocationSiteList(),
    476                         object);
    477 
    478   // We use a hammer (SkipWriteBarrier()) to indicate that we know the input
    479   // cell is really a Cell, and so no write barrier is needed.
    480   // TODO(mvstanton): Add a debug_code check to verify the input cell is really
    481   // a cell. (perhaps with a new instruction, HAssert).
    482   HInstruction* cell = GetParameter(0);
    483   HObjectAccess access = HObjectAccess::ForCellValue();
    484   store = Add<HStoreNamedField>(cell, access, object);
    485   store->SkipWriteBarrier();
    486   return cell;
    487 }
    488 
    489 
    490 Handle<Code> CreateAllocationSiteStub::GenerateCode() {
    491   return DoGenerateCode(this);
    492 }
    493 
    494 
    495 template <>
    496 HValue* CodeStubGraphBuilder<KeyedLoadFastElementStub>::BuildCodeStub() {
    497   HInstruction* load = BuildUncheckedMonomorphicElementAccess(
    498       GetParameter(0), GetParameter(1), NULL, NULL,
    499       casted_stub()->is_js_array(), casted_stub()->elements_kind(),
    500       false, NEVER_RETURN_HOLE, STANDARD_STORE);
    501   return load;
    502 }
    503 
    504 
    505 Handle<Code> KeyedLoadFastElementStub::GenerateCode() {
    506   return DoGenerateCode(this);
    507 }
    508 
    509 
    510 template<>
    511 HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() {
    512   Representation rep = casted_stub()->representation();
    513   HObjectAccess access = casted_stub()->is_inobject() ?
    514       HObjectAccess::ForJSObjectOffset(casted_stub()->offset(), rep) :
    515       HObjectAccess::ForBackingStoreOffset(casted_stub()->offset(), rep);
    516   return AddInstruction(BuildLoadNamedField(GetParameter(0), access, NULL));
    517 }
    518 
    519 
    520 Handle<Code> LoadFieldStub::GenerateCode() {
    521   return DoGenerateCode(this);
    522 }
    523 
    524 
    525 template<>
    526 HValue* CodeStubGraphBuilder<KeyedLoadFieldStub>::BuildCodeStub() {
    527   Representation rep = casted_stub()->representation();
    528   HObjectAccess access = casted_stub()->is_inobject() ?
    529       HObjectAccess::ForJSObjectOffset(casted_stub()->offset(), rep) :
    530       HObjectAccess::ForBackingStoreOffset(casted_stub()->offset(), rep);
    531   return AddInstruction(BuildLoadNamedField(GetParameter(0), access, NULL));
    532 }
    533 
    534 
    535 Handle<Code> KeyedLoadFieldStub::GenerateCode() {
    536   return DoGenerateCode(this);
    537 }
    538 
    539 
    540 template <>
    541 HValue* CodeStubGraphBuilder<KeyedStoreFastElementStub>::BuildCodeStub() {
    542   BuildUncheckedMonomorphicElementAccess(
    543       GetParameter(0), GetParameter(1), GetParameter(2), NULL,
    544       casted_stub()->is_js_array(), casted_stub()->elements_kind(),
    545       true, NEVER_RETURN_HOLE, casted_stub()->store_mode());
    546 
    547   return GetParameter(2);
    548 }
    549 
    550 
    551 Handle<Code> KeyedStoreFastElementStub::GenerateCode() {
    552   return DoGenerateCode(this);
    553 }
    554 
    555 
    556 template <>
    557 HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
    558   info()->MarkAsSavesCallerDoubles();
    559 
    560   BuildTransitionElementsKind(GetParameter(0),
    561                               GetParameter(1),
    562                               casted_stub()->from_kind(),
    563                               casted_stub()->to_kind(),
    564                               true);
    565 
    566   return GetParameter(0);
    567 }
    568 
    569 
    570 Handle<Code> TransitionElementsKindStub::GenerateCode() {
    571   return DoGenerateCode(this);
    572 }
    573 
    574 HValue* CodeStubGraphBuilderBase::BuildArrayConstructor(
    575     ElementsKind kind,
    576     ContextCheckMode context_mode,
    577     AllocationSiteOverrideMode override_mode,
    578     ArgumentClass argument_class) {
    579   HValue* constructor = GetParameter(ArrayConstructorStubBase::kConstructor);
    580   if (context_mode == CONTEXT_CHECK_REQUIRED) {
    581     HInstruction* array_function = BuildGetArrayFunction();
    582     ArrayContextChecker checker(this, constructor, array_function);
    583   }
    584 
    585   HValue* property_cell = GetParameter(ArrayConstructorStubBase::kPropertyCell);
    586   // Walk through the property cell to the AllocationSite
    587   HValue* alloc_site = Add<HLoadNamedField>(property_cell,
    588                                             HObjectAccess::ForCellValue());
    589   JSArrayBuilder array_builder(this, kind, alloc_site, constructor,
    590                                override_mode);
    591   HValue* result = NULL;
    592   switch (argument_class) {
    593     case NONE:
    594       result = array_builder.AllocateEmptyArray();
    595       break;
    596     case SINGLE:
    597       result = BuildArraySingleArgumentConstructor(&array_builder);
    598       break;
    599     case MULTIPLE:
    600       result = BuildArrayNArgumentsConstructor(&array_builder, kind);
    601       break;
    602   }
    603 
    604   return result;
    605 }
    606 
    607 
    608 HValue* CodeStubGraphBuilderBase::BuildInternalArrayConstructor(
    609     ElementsKind kind, ArgumentClass argument_class) {
    610   HValue* constructor = GetParameter(
    611       InternalArrayConstructorStubBase::kConstructor);
    612   JSArrayBuilder array_builder(this, kind, constructor);
    613 
    614   HValue* result = NULL;
    615   switch (argument_class) {
    616     case NONE:
    617       result = array_builder.AllocateEmptyArray();
    618       break;
    619     case SINGLE:
    620       result = BuildArraySingleArgumentConstructor(&array_builder);
    621       break;
    622     case MULTIPLE:
    623       result = BuildArrayNArgumentsConstructor(&array_builder, kind);
    624       break;
    625   }
    626   return result;
    627 }
    628 
    629 
    630 HValue* CodeStubGraphBuilderBase::BuildArraySingleArgumentConstructor(
    631     JSArrayBuilder* array_builder) {
    632   // Smi check and range check on the input arg.
    633   HValue* constant_one = graph()->GetConstant1();
    634   HValue* constant_zero = graph()->GetConstant0();
    635 
    636   HInstruction* elements = Add<HArgumentsElements>(false);
    637   HInstruction* argument = AddInstruction(
    638       new(zone()) HAccessArgumentsAt(elements, constant_one, constant_zero));
    639 
    640   HConstant* max_alloc_length =
    641       Add<HConstant>(JSObject::kInitialMaxFastElementArray);
    642   const int initial_capacity = JSArray::kPreallocatedArrayElements;
    643   HConstant* initial_capacity_node = New<HConstant>(initial_capacity);
    644   AddInstruction(initial_capacity_node);
    645 
    646   HInstruction* checked_arg = Add<HBoundsCheck>(argument, max_alloc_length);
    647   IfBuilder if_builder(this);
    648   if_builder.If<HCompareNumericAndBranch>(checked_arg, constant_zero,
    649                                           Token::EQ);
    650   if_builder.Then();
    651   Push(initial_capacity_node);  // capacity
    652   Push(constant_zero);  // length
    653   if_builder.Else();
    654   Push(checked_arg);  // capacity
    655   Push(checked_arg);  // length
    656   if_builder.End();
    657 
    658   // Figure out total size
    659   HValue* length = Pop();
    660   HValue* capacity = Pop();
    661   return array_builder->AllocateArray(capacity, length, true);
    662 }
    663 
    664 
    665 HValue* CodeStubGraphBuilderBase::BuildArrayNArgumentsConstructor(
    666     JSArrayBuilder* array_builder, ElementsKind kind) {
    667   // We need to fill with the hole if it's a smi array in the multi-argument
    668   // case because we might have to bail out while copying arguments into
    669   // the array because they aren't compatible with a smi array.
    670   // If it's a double array, no problem, and if it's fast then no
    671   // problem either because doubles are boxed.
    672   HValue* length = GetArgumentsLength();
    673   bool fill_with_hole = IsFastSmiElementsKind(kind);
    674   HValue* new_object = array_builder->AllocateArray(length,
    675                                                     length,
    676                                                     fill_with_hole);
    677   HValue* elements = array_builder->GetElementsLocation();
    678   ASSERT(elements != NULL);
    679 
    680   // Now populate the elements correctly.
    681   LoopBuilder builder(this,
    682                       context(),
    683                       LoopBuilder::kPostIncrement);
    684   HValue* start = graph()->GetConstant0();
    685   HValue* key = builder.BeginBody(start, length, Token::LT);
    686   HInstruction* argument_elements = Add<HArgumentsElements>(false);
    687   HInstruction* argument = AddInstruction(new(zone()) HAccessArgumentsAt(
    688       argument_elements, length, key));
    689 
    690   Add<HStoreKeyed>(elements, key, argument, kind);
    691   builder.EndBody();
    692   return new_object;
    693 }
    694 
    695 
    696 template <>
    697 HValue* CodeStubGraphBuilder<ArrayNoArgumentConstructorStub>::BuildCodeStub() {
    698   ElementsKind kind = casted_stub()->elements_kind();
    699   ContextCheckMode context_mode = casted_stub()->context_mode();
    700   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
    701   return BuildArrayConstructor(kind, context_mode, override_mode, NONE);
    702 }
    703 
    704 
    705 Handle<Code> ArrayNoArgumentConstructorStub::GenerateCode() {
    706   return DoGenerateCode(this);
    707 }
    708 
    709 
    710 template <>
    711 HValue* CodeStubGraphBuilder<ArraySingleArgumentConstructorStub>::
    712     BuildCodeStub() {
    713   ElementsKind kind = casted_stub()->elements_kind();
    714   ContextCheckMode context_mode = casted_stub()->context_mode();
    715   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
    716   return BuildArrayConstructor(kind, context_mode, override_mode, SINGLE);
    717 }
    718 
    719 
    720 Handle<Code> ArraySingleArgumentConstructorStub::GenerateCode() {
    721   return DoGenerateCode(this);
    722 }
    723 
    724 
    725 template <>
    726 HValue* CodeStubGraphBuilder<ArrayNArgumentsConstructorStub>::BuildCodeStub() {
    727   ElementsKind kind = casted_stub()->elements_kind();
    728   ContextCheckMode context_mode = casted_stub()->context_mode();
    729   AllocationSiteOverrideMode override_mode = casted_stub()->override_mode();
    730   return BuildArrayConstructor(kind, context_mode, override_mode, MULTIPLE);
    731 }
    732 
    733 
    734 Handle<Code> ArrayNArgumentsConstructorStub::GenerateCode() {
    735   return DoGenerateCode(this);
    736 }
    737 
    738 
    739 template <>
    740 HValue* CodeStubGraphBuilder<InternalArrayNoArgumentConstructorStub>::
    741     BuildCodeStub() {
    742   ElementsKind kind = casted_stub()->elements_kind();
    743   return BuildInternalArrayConstructor(kind, NONE);
    744 }
    745 
    746 
    747 Handle<Code> InternalArrayNoArgumentConstructorStub::GenerateCode() {
    748   return DoGenerateCode(this);
    749 }
    750 
    751 
    752 template <>
    753 HValue* CodeStubGraphBuilder<InternalArraySingleArgumentConstructorStub>::
    754     BuildCodeStub() {
    755   ElementsKind kind = casted_stub()->elements_kind();
    756   return BuildInternalArrayConstructor(kind, SINGLE);
    757 }
    758 
    759 
    760 Handle<Code> InternalArraySingleArgumentConstructorStub::GenerateCode() {
    761   return DoGenerateCode(this);
    762 }
    763 
    764 
    765 template <>
    766 HValue* CodeStubGraphBuilder<InternalArrayNArgumentsConstructorStub>::
    767     BuildCodeStub() {
    768   ElementsKind kind = casted_stub()->elements_kind();
    769   return BuildInternalArrayConstructor(kind, MULTIPLE);
    770 }
    771 
    772 
    773 Handle<Code> InternalArrayNArgumentsConstructorStub::GenerateCode() {
    774   return DoGenerateCode(this);
    775 }
    776 
    777 
    778 template <>
    779 HValue* CodeStubGraphBuilder<CompareNilICStub>::BuildCodeInitializedStub() {
    780   Isolate* isolate = graph()->isolate();
    781   CompareNilICStub* stub = casted_stub();
    782   HIfContinuation continuation;
    783   Handle<Map> sentinel_map(isolate->heap()->meta_map());
    784   Handle<Type> type = stub->GetType(isolate, sentinel_map);
    785   BuildCompareNil(GetParameter(0), type, RelocInfo::kNoPosition, &continuation);
    786   IfBuilder if_nil(this, &continuation);
    787   if_nil.Then();
    788   if (continuation.IsFalseReachable()) {
    789     if_nil.Else();
    790     if_nil.Return(graph()->GetConstant0());
    791   }
    792   if_nil.End();
    793   return continuation.IsTrueReachable()
    794       ? graph()->GetConstant1()
    795       : graph()->GetConstantUndefined();
    796 }
    797 
    798 
    799 Handle<Code> CompareNilICStub::GenerateCode() {
    800   return DoGenerateCode(this);
    801 }
    802 
    803 
    804 template <>
    805 HValue* CodeStubGraphBuilder<ToBooleanStub>::BuildCodeInitializedStub() {
    806   ToBooleanStub* stub = casted_stub();
    807 
    808   IfBuilder if_true(this);
    809   if_true.If<HBranch>(GetParameter(0), stub->GetTypes());
    810   if_true.Then();
    811   if_true.Return(graph()->GetConstant1());
    812   if_true.Else();
    813   if_true.End();
    814   return graph()->GetConstant0();
    815 }
    816 
    817 
    818 Handle<Code> ToBooleanStub::GenerateCode() {
    819   return DoGenerateCode(this);
    820 }
    821 
    822 
    823 template <>
    824 HValue* CodeStubGraphBuilder<StoreGlobalStub>::BuildCodeInitializedStub() {
    825   StoreGlobalStub* stub = casted_stub();
    826   Handle<Object> hole(isolate()->heap()->the_hole_value(), isolate());
    827   Handle<Object> placeholer_value(Smi::FromInt(0), isolate());
    828   Handle<PropertyCell> placeholder_cell =
    829       isolate()->factory()->NewPropertyCell(placeholer_value);
    830 
    831   HParameter* receiver = GetParameter(0);
    832   HParameter* value = GetParameter(2);
    833 
    834   // Check that the map of the global has not changed: use a placeholder map
    835   // that will be replaced later with the global object's map.
    836   Handle<Map> placeholder_map = isolate()->factory()->meta_map();
    837   Add<HCheckMaps>(receiver, placeholder_map, top_info());
    838 
    839   HValue* cell = Add<HConstant>(placeholder_cell);
    840   HObjectAccess access(HObjectAccess::ForCellPayload(isolate()));
    841   HValue* cell_contents = Add<HLoadNamedField>(cell, access);
    842 
    843   if (stub->is_constant()) {
    844     IfBuilder builder(this);
    845     builder.If<HCompareObjectEqAndBranch>(cell_contents, value);
    846     builder.Then();
    847     builder.ElseDeopt("Unexpected cell contents in constant global store");
    848     builder.End();
    849   } else {
    850     // Load the payload of the global parameter cell. A hole indicates that the
    851     // property has been deleted and that the store must be handled by the
    852     // runtime.
    853     IfBuilder builder(this);
    854     HValue* hole_value = Add<HConstant>(hole);
    855     builder.If<HCompareObjectEqAndBranch>(cell_contents, hole_value);
    856     builder.Then();
    857     builder.Deopt("Unexpected cell contents in global store");
    858     builder.Else();
    859     Add<HStoreNamedField>(cell, access, value);
    860     builder.End();
    861   }
    862 
    863   return value;
    864 }
    865 
    866 
    867 Handle<Code> StoreGlobalStub::GenerateCode() {
    868   return DoGenerateCode(this);
    869 }
    870 
    871 
    872 template<>
    873 HValue* CodeStubGraphBuilder<ElementsTransitionAndStoreStub>::BuildCodeStub() {
    874   HValue* value = GetParameter(0);
    875   HValue* map = GetParameter(1);
    876   HValue* key = GetParameter(2);
    877   HValue* object = GetParameter(3);
    878 
    879   if (FLAG_trace_elements_transitions) {
    880     // Tracing elements transitions is the job of the runtime.
    881     Add<HDeoptimize>("Deopt due to --trace-elements-transitions",
    882                      Deoptimizer::EAGER);
    883   } else {
    884     info()->MarkAsSavesCallerDoubles();
    885 
    886     BuildTransitionElementsKind(object, map,
    887                                 casted_stub()->from_kind(),
    888                                 casted_stub()->to_kind(),
    889                                 casted_stub()->is_jsarray());
    890 
    891     BuildUncheckedMonomorphicElementAccess(object, key, value, NULL,
    892                                           casted_stub()->is_jsarray(),
    893                                           casted_stub()->to_kind(),
    894                                           true, ALLOW_RETURN_HOLE,
    895                                           casted_stub()->store_mode());
    896   }
    897 
    898   return value;
    899 }
    900 
    901 
    902 Handle<Code> ElementsTransitionAndStoreStub::GenerateCode() {
    903   return DoGenerateCode(this);
    904 }
    905 
    906 
    907 } }  // namespace v8::internal
    908