Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/code-stubs.h"
      6 
      7 #include <memory>
      8 
      9 #include "src/bailout-reason.h"
     10 #include "src/code-factory.h"
     11 #include "src/crankshaft/hydrogen.h"
     12 #include "src/crankshaft/lithium.h"
     13 #include "src/field-index.h"
     14 #include "src/ic/ic.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 
     20 static LChunk* OptimizeGraph(HGraph* graph) {
     21   DisallowHeapAllocation no_allocation;
     22   DisallowHandleAllocation no_handles;
     23   DisallowHandleDereference no_deref;
     24 
     25   DCHECK(graph != NULL);
     26   BailoutReason bailout_reason = kNoReason;
     27   if (!graph->Optimize(&bailout_reason)) {
     28     FATAL(GetBailoutReason(bailout_reason));
     29   }
     30   LChunk* chunk = LChunk::NewChunk(graph);
     31   if (chunk == NULL) {
     32     FATAL(GetBailoutReason(graph->info()->bailout_reason()));
     33   }
     34   return chunk;
     35 }
     36 
     37 
     38 class CodeStubGraphBuilderBase : public HGraphBuilder {
     39  public:
     40   explicit CodeStubGraphBuilderBase(CompilationInfo* info, CodeStub* code_stub)
     41       : HGraphBuilder(info, code_stub->GetCallInterfaceDescriptor(), false),
     42         arguments_length_(NULL),
     43         info_(info),
     44         code_stub_(code_stub),
     45         descriptor_(code_stub),
     46         context_(NULL) {
     47     int parameter_count = GetParameterCount();
     48     parameters_.reset(new HParameter*[parameter_count]);
     49   }
     50   virtual bool BuildGraph();
     51 
     52  protected:
     53   virtual HValue* BuildCodeStub() = 0;
     54   int GetParameterCount() const { return descriptor_.GetParameterCount(); }
     55   int GetRegisterParameterCount() const {
     56     return descriptor_.GetRegisterParameterCount();
     57   }
     58   HParameter* GetParameter(int parameter) {
     59     DCHECK(parameter < GetParameterCount());
     60     return parameters_[parameter];
     61   }
     62   Representation GetParameterRepresentation(int parameter) {
     63     return RepresentationFromMachineType(
     64         descriptor_.GetParameterType(parameter));
     65   }
     66   bool IsParameterCountRegister(int index) const {
     67     return descriptor_.GetRegisterParameter(index)
     68         .is(descriptor_.stack_parameter_count());
     69   }
     70   HValue* GetArgumentsLength() {
     71     // This is initialized in BuildGraph()
     72     DCHECK(arguments_length_ != NULL);
     73     return arguments_length_;
     74   }
     75   CompilationInfo* info() { return info_; }
     76   CodeStub* stub() { return code_stub_; }
     77   HContext* context() { return context_; }
     78   Isolate* isolate() { return info_->isolate(); }
     79 
     80   HLoadNamedField* BuildLoadNamedField(HValue* object, FieldIndex index);
     81   void BuildStoreNamedField(HValue* object, HValue* value, FieldIndex index,
     82                             Representation representation,
     83                             bool transition_to_field);
     84 
     85   HValue* BuildPushElement(HValue* object, HValue* argc,
     86                            HValue* argument_elements, ElementsKind kind);
     87 
     88   HValue* BuildToString(HValue* input, bool convert);
     89   HValue* BuildToPrimitive(HValue* input, HValue* input_map);
     90 
     91  private:
     92   std::unique_ptr<HParameter* []> parameters_;
     93   HValue* arguments_length_;
     94   CompilationInfo* info_;
     95   CodeStub* code_stub_;
     96   CodeStubDescriptor descriptor_;
     97   HContext* context_;
     98 };
     99 
    100 
    101 bool CodeStubGraphBuilderBase::BuildGraph() {
    102   // Update the static counter each time a new code stub is generated.
    103   isolate()->counters()->code_stubs()->Increment();
    104 
    105   if (FLAG_trace_hydrogen_stubs) {
    106     const char* name = CodeStub::MajorName(stub()->MajorKey());
    107     PrintF("-----------------------------------------------------------\n");
    108     PrintF("Compiling stub %s using hydrogen\n", name);
    109     isolate()->GetHTracer()->TraceCompilation(info());
    110   }
    111 
    112   int param_count = GetParameterCount();
    113   int register_param_count = GetRegisterParameterCount();
    114   HEnvironment* start_environment = graph()->start_environment();
    115   HBasicBlock* next_block = CreateBasicBlock(start_environment);
    116   Goto(next_block);
    117   next_block->SetJoinId(BailoutId::StubEntry());
    118   set_current_block(next_block);
    119 
    120   bool runtime_stack_params = descriptor_.stack_parameter_count().is_valid();
    121   HInstruction* stack_parameter_count = NULL;
    122   for (int i = 0; i < param_count; ++i) {
    123     Representation r = GetParameterRepresentation(i);
    124     HParameter* param;
    125     if (i >= register_param_count) {
    126       param = Add<HParameter>(i - register_param_count,
    127                               HParameter::STACK_PARAMETER, r);
    128     } else {
    129       param = Add<HParameter>(i, HParameter::REGISTER_PARAMETER, r);
    130     }
    131     start_environment->Bind(i, param);
    132     parameters_[i] = param;
    133     if (i < register_param_count && IsParameterCountRegister(i)) {
    134       param->set_type(HType::Smi());
    135       stack_parameter_count = param;
    136       arguments_length_ = stack_parameter_count;
    137     }
    138   }
    139 
    140   DCHECK(!runtime_stack_params || arguments_length_ != NULL);
    141   if (!runtime_stack_params) {
    142     stack_parameter_count =
    143         Add<HConstant>(param_count - register_param_count - 1);
    144     // graph()->GetConstantMinus1();
    145     arguments_length_ = graph()->GetConstant0();
    146   }
    147 
    148   context_ = Add<HContext>();
    149   start_environment->BindContext(context_);
    150   start_environment->Bind(param_count, context_);
    151 
    152   Add<HSimulate>(BailoutId::StubEntry());
    153 
    154   NoObservableSideEffectsScope no_effects(this);
    155 
    156   HValue* return_value = BuildCodeStub();
    157 
    158   // We might have extra expressions to pop from the stack in addition to the
    159   // arguments above.
    160   HInstruction* stack_pop_count = stack_parameter_count;
    161   if (descriptor_.function_mode() == JS_FUNCTION_STUB_MODE) {
    162     if (!stack_parameter_count->IsConstant() &&
    163         descriptor_.hint_stack_parameter_count() < 0) {
    164       HInstruction* constant_one = graph()->GetConstant1();
    165       stack_pop_count = AddUncasted<HAdd>(stack_parameter_count, constant_one);
    166       stack_pop_count->ClearFlag(HValue::kCanOverflow);
    167       // TODO(mvstanton): verify that stack_parameter_count+1 really fits in a
    168       // smi.
    169     } else {
    170       int count = descriptor_.hint_stack_parameter_count();
    171       stack_pop_count = Add<HConstant>(count);
    172     }
    173   }
    174 
    175   if (current_block() != NULL) {
    176     HReturn* hreturn_instruction = New<HReturn>(return_value,
    177                                                 stack_pop_count);
    178     FinishCurrentBlock(hreturn_instruction);
    179   }
    180   return true;
    181 }
    182 
    183 
    184 template <class Stub>
    185 class CodeStubGraphBuilder: public CodeStubGraphBuilderBase {
    186  public:
    187   explicit CodeStubGraphBuilder(CompilationInfo* info, CodeStub* stub)
    188       : CodeStubGraphBuilderBase(info, stub) {}
    189 
    190   typedef typename Stub::Descriptor Descriptor;
    191 
    192  protected:
    193   virtual HValue* BuildCodeStub() {
    194     if (casted_stub()->IsUninitialized()) {
    195       return BuildCodeUninitializedStub();
    196     } else {
    197       return BuildCodeInitializedStub();
    198     }
    199   }
    200 
    201   virtual HValue* BuildCodeInitializedStub() {
    202     UNIMPLEMENTED();
    203     return NULL;
    204   }
    205 
    206   virtual HValue* BuildCodeUninitializedStub() {
    207     // Force a deopt that falls back to the runtime.
    208     HValue* undefined = graph()->GetConstantUndefined();
    209     IfBuilder builder(this);
    210     builder.IfNot<HCompareObjectEqAndBranch, HValue*>(undefined, undefined);
    211     builder.Then();
    212     builder.ElseDeopt(DeoptimizeReason::kForcedDeoptToRuntime);
    213     return undefined;
    214   }
    215 
    216   Stub* casted_stub() { return static_cast<Stub*>(stub()); }
    217 };
    218 
    219 
    220 Handle<Code> HydrogenCodeStub::GenerateLightweightMissCode(
    221     ExternalReference miss) {
    222   Factory* factory = isolate()->factory();
    223 
    224   // Generate the new code.
    225   MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
    226 
    227   {
    228     // Update the static counter each time a new code stub is generated.
    229     isolate()->counters()->code_stubs()->Increment();
    230 
    231     // Generate the code for the stub.
    232     masm.set_generating_stub(true);
    233     // TODO(yangguo): remove this once we can serialize IC stubs.
    234     masm.enable_serializer();
    235     NoCurrentFrameScope scope(&masm);
    236     GenerateLightweightMiss(&masm, miss);
    237   }
    238 
    239   // Create the code object.
    240   CodeDesc desc;
    241   masm.GetCode(&desc);
    242 
    243   // Copy the generated code into a heap object.
    244   Handle<Code> new_object = factory->NewCode(
    245       desc, GetCodeFlags(), masm.CodeObject(), NeedsImmovableCode());
    246   return new_object;
    247 }
    248 
    249 Handle<Code> HydrogenCodeStub::GenerateRuntimeTailCall(
    250     CodeStubDescriptor* descriptor) {
    251   const char* name = CodeStub::MajorName(MajorKey());
    252   Zone zone(isolate()->allocator(), ZONE_NAME);
    253   CallInterfaceDescriptor interface_descriptor(GetCallInterfaceDescriptor());
    254   CodeStubAssembler assembler(isolate(), &zone, interface_descriptor,
    255                               GetCodeFlags(), name);
    256   int total_params = interface_descriptor.GetStackParameterCount() +
    257                      interface_descriptor.GetRegisterParameterCount();
    258   switch (total_params) {
    259     case 0:
    260       assembler.TailCallRuntime(descriptor->miss_handler_id(),
    261                                 assembler.Parameter(0));
    262       break;
    263     case 1:
    264       assembler.TailCallRuntime(descriptor->miss_handler_id(),
    265                                 assembler.Parameter(1), assembler.Parameter(0));
    266       break;
    267     case 2:
    268       assembler.TailCallRuntime(descriptor->miss_handler_id(),
    269                                 assembler.Parameter(2), assembler.Parameter(0),
    270                                 assembler.Parameter(1));
    271       break;
    272     case 3:
    273       assembler.TailCallRuntime(descriptor->miss_handler_id(),
    274                                 assembler.Parameter(3), assembler.Parameter(0),
    275                                 assembler.Parameter(1), assembler.Parameter(2));
    276       break;
    277     case 4:
    278       assembler.TailCallRuntime(descriptor->miss_handler_id(),
    279                                 assembler.Parameter(4), assembler.Parameter(0),
    280                                 assembler.Parameter(1), assembler.Parameter(2),
    281                                 assembler.Parameter(3));
    282       break;
    283     default:
    284       UNIMPLEMENTED();
    285       break;
    286   }
    287   return assembler.GenerateCode();
    288 }
    289 
    290 template <class Stub>
    291 static Handle<Code> DoGenerateCode(Stub* stub) {
    292   Isolate* isolate = stub->isolate();
    293   CodeStubDescriptor descriptor(stub);
    294 
    295   if (FLAG_minimal && descriptor.has_miss_handler()) {
    296     return stub->GenerateRuntimeTailCall(&descriptor);
    297   }
    298 
    299   // If we are uninitialized we can use a light-weight stub to enter
    300   // the runtime that is significantly faster than using the standard
    301   // stub-failure deopt mechanism.
    302   if (stub->IsUninitialized() && descriptor.has_miss_handler()) {
    303     DCHECK(!descriptor.stack_parameter_count().is_valid());
    304     return stub->GenerateLightweightMissCode(descriptor.miss_handler());
    305   }
    306   base::ElapsedTimer timer;
    307   if (FLAG_profile_hydrogen_code_stub_compilation) {
    308     timer.Start();
    309   }
    310   Zone zone(isolate->allocator(), ZONE_NAME);
    311   CompilationInfo info(CStrVector(CodeStub::MajorName(stub->MajorKey())),
    312                        isolate, &zone, stub->GetCodeFlags());
    313   // Parameter count is number of stack parameters.
    314   int parameter_count = descriptor.GetStackParameterCount();
    315   if (descriptor.function_mode() == NOT_JS_FUNCTION_STUB_MODE) {
    316     parameter_count--;
    317   }
    318   info.set_parameter_count(parameter_count);
    319   CodeStubGraphBuilder<Stub> builder(&info, stub);
    320   LChunk* chunk = OptimizeGraph(builder.CreateGraph());
    321   Handle<Code> code = chunk->Codegen();
    322   if (FLAG_profile_hydrogen_code_stub_compilation) {
    323     OFStream os(stdout);
    324     os << "[Lazy compilation of " << stub << " took "
    325        << timer.Elapsed().InMillisecondsF() << " ms]" << std::endl;
    326   }
    327   return code;
    328 }
    329 
    330 
    331 HValue* CodeStubGraphBuilderBase::BuildPushElement(HValue* object, HValue* argc,
    332                                                    HValue* argument_elements,
    333                                                    ElementsKind kind) {
    334   // Precheck whether all elements fit into the array.
    335   if (!IsFastObjectElementsKind(kind)) {
    336     LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
    337     HValue* start = graph()->GetConstant0();
    338     HValue* key = builder.BeginBody(start, argc, Token::LT);
    339     {
    340       HInstruction* argument =
    341           Add<HAccessArgumentsAt>(argument_elements, argc, key);
    342       IfBuilder can_store(this);
    343       can_store.IfNot<HIsSmiAndBranch>(argument);
    344       if (IsFastDoubleElementsKind(kind)) {
    345         can_store.And();
    346         can_store.IfNot<HCompareMap>(argument,
    347                                      isolate()->factory()->heap_number_map());
    348       }
    349       can_store.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    350       can_store.End();
    351     }
    352     builder.EndBody();
    353   }
    354 
    355   HValue* length = Add<HLoadNamedField>(object, nullptr,
    356                                         HObjectAccess::ForArrayLength(kind));
    357   HValue* new_length = AddUncasted<HAdd>(length, argc);
    358   HValue* max_key = AddUncasted<HSub>(new_length, graph()->GetConstant1());
    359 
    360   HValue* elements = Add<HLoadNamedField>(object, nullptr,
    361                                           HObjectAccess::ForElementsPointer());
    362   elements = BuildCheckForCapacityGrow(object, elements, kind, length, max_key,
    363                                        true, STORE);
    364 
    365   LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
    366   HValue* start = graph()->GetConstant0();
    367   HValue* key = builder.BeginBody(start, argc, Token::LT);
    368   {
    369     HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key);
    370     HValue* index = AddUncasted<HAdd>(key, length);
    371     AddElementAccess(elements, index, argument, object, nullptr, kind, STORE);
    372   }
    373   builder.EndBody();
    374   return new_length;
    375 }
    376 
    377 template <>
    378 HValue* CodeStubGraphBuilder<FastArrayPushStub>::BuildCodeStub() {
    379   // TODO(verwaest): Fix deoptimizer messages.
    380   HValue* argc = GetArgumentsLength();
    381 
    382   HInstruction* argument_elements = Add<HArgumentsElements>(false, false);
    383   HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc,
    384                                                  graph()->GetConstantMinus1());
    385   BuildCheckHeapObject(object);
    386   HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
    387   Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_ARRAY);
    388 
    389   // Disallow pushing onto prototypes. It might be the JSArray prototype.
    390   // Disallow pushing onto non-extensible objects.
    391   {
    392     HValue* bit_field2 =
    393         Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
    394     HValue* mask =
    395         Add<HConstant>(static_cast<int>(Map::IsPrototypeMapBits::kMask) |
    396                        (1 << Map::kIsExtensible));
    397     HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field2, mask);
    398     IfBuilder check(this);
    399     check.If<HCompareNumericAndBranch>(
    400         bits, Add<HConstant>(1 << Map::kIsExtensible), Token::NE);
    401     check.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    402     check.End();
    403   }
    404 
    405   // Disallow pushing onto arrays in dictionary named property mode. We need to
    406   // figure out whether the length property is still writable.
    407   {
    408     HValue* bit_field3 =
    409         Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3());
    410     HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask));
    411     HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask);
    412     IfBuilder check(this);
    413     check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ);
    414     check.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    415     check.End();
    416   }
    417 
    418   // Check whether the length property is writable. The length property is the
    419   // only default named property on arrays. It's nonconfigurable, hence is
    420   // guaranteed to stay the first property.
    421   {
    422     HValue* descriptors =
    423         Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors());
    424     HValue* details = Add<HLoadKeyed>(
    425         descriptors, Add<HConstant>(DescriptorArray::ToDetailsIndex(0)),
    426         nullptr, nullptr, FAST_SMI_ELEMENTS);
    427     HValue* mask =
    428         Add<HConstant>(READ_ONLY << PropertyDetails::AttributesField::kShift);
    429     HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, details, mask);
    430     IfBuilder readonly(this);
    431     readonly.If<HCompareNumericAndBranch>(bit, mask, Token::EQ);
    432     readonly.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    433     readonly.End();
    434   }
    435 
    436   HValue* null = Add<HLoadRoot>(Heap::kNullValueRootIndex);
    437   HValue* empty = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
    438   environment()->Push(map);
    439   LoopBuilder check_prototypes(this);
    440   check_prototypes.BeginBody(1);
    441   {
    442     HValue* parent_map = environment()->Pop();
    443     HValue* prototype = Add<HLoadNamedField>(parent_map, nullptr,
    444                                              HObjectAccess::ForPrototype());
    445 
    446     IfBuilder is_null(this);
    447     is_null.If<HCompareObjectEqAndBranch>(prototype, null);
    448     is_null.Then();
    449     check_prototypes.Break();
    450     is_null.End();
    451 
    452     HValue* prototype_map =
    453         Add<HLoadNamedField>(prototype, nullptr, HObjectAccess::ForMap());
    454     HValue* instance_type = Add<HLoadNamedField>(
    455         prototype_map, nullptr, HObjectAccess::ForMapInstanceType());
    456     IfBuilder check_instance_type(this);
    457     check_instance_type.If<HCompareNumericAndBranch>(
    458         instance_type, Add<HConstant>(LAST_CUSTOM_ELEMENTS_RECEIVER),
    459         Token::LTE);
    460     check_instance_type.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    461     check_instance_type.End();
    462 
    463     HValue* elements = Add<HLoadNamedField>(
    464         prototype, nullptr, HObjectAccess::ForElementsPointer());
    465     IfBuilder no_elements(this);
    466     no_elements.IfNot<HCompareObjectEqAndBranch>(elements, empty);
    467     no_elements.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    468     no_elements.End();
    469 
    470     environment()->Push(prototype_map);
    471   }
    472   check_prototypes.EndBody();
    473 
    474   HValue* bit_field2 =
    475       Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2());
    476   HValue* kind = BuildDecodeField<Map::ElementsKindBits>(bit_field2);
    477 
    478   // Below we only check the upper bound of the relevant ranges to include both
    479   // holey and non-holey versions. We check them in order smi, object, double
    480   // since smi < object < double.
    481   STATIC_ASSERT(FAST_SMI_ELEMENTS < FAST_HOLEY_SMI_ELEMENTS);
    482   STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS < FAST_HOLEY_ELEMENTS);
    483   STATIC_ASSERT(FAST_ELEMENTS < FAST_HOLEY_ELEMENTS);
    484   STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS);
    485   STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FAST_HOLEY_DOUBLE_ELEMENTS);
    486   IfBuilder has_smi_elements(this);
    487   has_smi_elements.If<HCompareNumericAndBranch>(
    488       kind, Add<HConstant>(FAST_HOLEY_SMI_ELEMENTS), Token::LTE);
    489   has_smi_elements.Then();
    490   {
    491     HValue* new_length = BuildPushElement(object, argc, argument_elements,
    492                                           FAST_HOLEY_SMI_ELEMENTS);
    493     environment()->Push(new_length);
    494   }
    495   has_smi_elements.Else();
    496   {
    497     IfBuilder has_object_elements(this);
    498     has_object_elements.If<HCompareNumericAndBranch>(
    499         kind, Add<HConstant>(FAST_HOLEY_ELEMENTS), Token::LTE);
    500     has_object_elements.Then();
    501     {
    502       HValue* new_length = BuildPushElement(object, argc, argument_elements,
    503                                             FAST_HOLEY_ELEMENTS);
    504       environment()->Push(new_length);
    505     }
    506     has_object_elements.Else();
    507     {
    508       IfBuilder has_double_elements(this);
    509       has_double_elements.If<HCompareNumericAndBranch>(
    510           kind, Add<HConstant>(FAST_HOLEY_DOUBLE_ELEMENTS), Token::LTE);
    511       has_double_elements.Then();
    512       {
    513         HValue* new_length = BuildPushElement(object, argc, argument_elements,
    514                                               FAST_HOLEY_DOUBLE_ELEMENTS);
    515         environment()->Push(new_length);
    516       }
    517       has_double_elements.ElseDeopt(DeoptimizeReason::kFastPathFailed);
    518       has_double_elements.End();
    519     }
    520     has_object_elements.End();
    521   }
    522   has_smi_elements.End();
    523 
    524   return environment()->Pop();
    525 }
    526 
    527 Handle<Code> FastArrayPushStub::GenerateCode() { return DoGenerateCode(this); }
    528 
    529 template <>
    530 HValue* CodeStubGraphBuilder<FastFunctionBindStub>::BuildCodeStub() {
    531   // TODO(verwaest): Fix deoptimizer messages.
    532   HValue* argc = GetArgumentsLength();
    533   HInstruction* argument_elements = Add<HArgumentsElements>(false, false);
    534   HInstruction* object = Add<HAccessArgumentsAt>(argument_elements, argc,
    535                                                  graph()->GetConstantMinus1());
    536   BuildCheckHeapObject(object);
    537   HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap());
    538   Add<HCheckInstanceType>(object, HCheckInstanceType::IS_JS_FUNCTION);
    539 
    540   // Disallow binding of slow-mode functions. We need to figure out whether the
    541   // length and name property are in the original state.
    542   {
    543     HValue* bit_field3 =
    544         Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3());
    545     HValue* mask = Add<HConstant>(static_cast<int>(Map::DictionaryMap::kMask));
    546     HValue* bit = AddUncasted<HBitwise>(Token::BIT_AND, bit_field3, mask);
    547     IfBuilder check(this);
    548     check.If<HCompareNumericAndBranch>(bit, mask, Token::EQ);
    549     check.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    550     check.End();
    551   }
    552 
    553   // Check whether the length and name properties are still present as
    554   // AccessorInfo objects. In that case, their value can be recomputed even if
    555   // the actual value on the object changes.
    556   {
    557     HValue* descriptors =
    558         Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapDescriptors());
    559 
    560     HValue* descriptors_length = Add<HLoadNamedField>(
    561         descriptors, nullptr, HObjectAccess::ForFixedArrayLength());
    562     IfBuilder range(this);
    563     range.If<HCompareNumericAndBranch>(descriptors_length,
    564                                        graph()->GetConstant1(), Token::LTE);
    565     range.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    566     range.End();
    567 
    568     // Verify .length.
    569     const int length_index = JSFunction::kLengthDescriptorIndex;
    570     HValue* maybe_length = Add<HLoadKeyed>(
    571         descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(length_index)),
    572         nullptr, nullptr, FAST_ELEMENTS);
    573     Unique<Name> length_string = Unique<Name>::CreateUninitialized(
    574         isolate()->factory()->length_string());
    575     Add<HCheckValue>(maybe_length, length_string, false);
    576 
    577     HValue* maybe_length_accessor = Add<HLoadKeyed>(
    578         descriptors,
    579         Add<HConstant>(DescriptorArray::ToValueIndex(length_index)), nullptr,
    580         nullptr, FAST_ELEMENTS);
    581     BuildCheckHeapObject(maybe_length_accessor);
    582     Add<HCheckMaps>(maybe_length_accessor,
    583                     isolate()->factory()->accessor_info_map());
    584 
    585     // Verify .name.
    586     const int name_index = JSFunction::kNameDescriptorIndex;
    587     HValue* maybe_name = Add<HLoadKeyed>(
    588         descriptors, Add<HConstant>(DescriptorArray::ToKeyIndex(name_index)),
    589         nullptr, nullptr, FAST_ELEMENTS);
    590     Unique<Name> name_string =
    591         Unique<Name>::CreateUninitialized(isolate()->factory()->name_string());
    592     Add<HCheckValue>(maybe_name, name_string, false);
    593 
    594     HValue* maybe_name_accessor = Add<HLoadKeyed>(
    595         descriptors, Add<HConstant>(DescriptorArray::ToValueIndex(name_index)),
    596         nullptr, nullptr, FAST_ELEMENTS);
    597     BuildCheckHeapObject(maybe_name_accessor);
    598     Add<HCheckMaps>(maybe_name_accessor,
    599                     isolate()->factory()->accessor_info_map());
    600   }
    601 
    602   // Choose the right bound function map based on whether the target is
    603   // constructable.
    604   {
    605     HValue* bit_field =
    606         Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField());
    607     HValue* mask = Add<HConstant>(static_cast<int>(1 << Map::kIsConstructor));
    608     HValue* bits = AddUncasted<HBitwise>(Token::BIT_AND, bit_field, mask);
    609 
    610     HValue* native_context = BuildGetNativeContext();
    611     IfBuilder is_constructor(this);
    612     is_constructor.If<HCompareNumericAndBranch>(bits, mask, Token::EQ);
    613     is_constructor.Then();
    614     {
    615       HValue* map = Add<HLoadNamedField>(
    616           native_context, nullptr,
    617           HObjectAccess::ForContextSlot(
    618               Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX));
    619       environment()->Push(map);
    620     }
    621     is_constructor.Else();
    622     {
    623       HValue* map = Add<HLoadNamedField>(
    624           native_context, nullptr,
    625           HObjectAccess::ForContextSlot(
    626               Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX));
    627       environment()->Push(map);
    628     }
    629     is_constructor.End();
    630   }
    631   HValue* bound_function_map = environment()->Pop();
    632 
    633   // Verify that __proto__ matches that of a the target bound function.
    634   {
    635     HValue* prototype =
    636         Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForPrototype());
    637     HValue* expected_prototype = Add<HLoadNamedField>(
    638         bound_function_map, nullptr, HObjectAccess::ForPrototype());
    639     IfBuilder equal_prototype(this);
    640     equal_prototype.IfNot<HCompareObjectEqAndBranch>(prototype,
    641                                                      expected_prototype);
    642     equal_prototype.ThenDeopt(DeoptimizeReason::kFastPathFailed);
    643     equal_prototype.End();
    644   }
    645 
    646   // Allocate the arguments array.
    647   IfBuilder empty_args(this);
    648   empty_args.If<HCompareNumericAndBranch>(argc, graph()->GetConstant1(),
    649                                           Token::LTE);
    650   empty_args.Then();
    651   { environment()->Push(Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex)); }
    652   empty_args.Else();
    653   {
    654     HValue* elements_length = AddUncasted<HSub>(argc, graph()->GetConstant1());
    655     HValue* elements =
    656         BuildAllocateAndInitializeArray(FAST_ELEMENTS, elements_length);
    657 
    658     LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement);
    659     HValue* start = graph()->GetConstant1();
    660     HValue* key = builder.BeginBody(start, argc, Token::LT);
    661     {
    662       HValue* argument = Add<HAccessArgumentsAt>(argument_elements, argc, key);
    663       HValue* index = AddUncasted<HSub>(key, graph()->GetConstant1());
    664       AddElementAccess(elements, index, argument, elements, nullptr,
    665                        FAST_ELEMENTS, STORE);
    666     }
    667     builder.EndBody();
    668     environment()->Push(elements);
    669   }
    670   empty_args.End();
    671   HValue* elements = environment()->Pop();
    672 
    673   // Find the 'this' to bind.
    674   IfBuilder no_receiver(this);
    675   no_receiver.If<HCompareNumericAndBranch>(argc, graph()->GetConstant0(),
    676                                            Token::EQ);
    677   no_receiver.Then();
    678   { environment()->Push(Add<HLoadRoot>(Heap::kUndefinedValueRootIndex)); }
    679   no_receiver.Else();
    680   {
    681     environment()->Push(Add<HAccessArgumentsAt>(argument_elements, argc,
    682                                                 graph()->GetConstant0()));
    683   }
    684   no_receiver.End();
    685   HValue* receiver = environment()->Pop();
    686 
    687   // Allocate the resulting bound function.
    688   HValue* size = Add<HConstant>(JSBoundFunction::kSize);
    689   HValue* bound_function =
    690       Add<HAllocate>(size, HType::JSObject(), NOT_TENURED,
    691                      JS_BOUND_FUNCTION_TYPE, graph()->GetConstant0());
    692   Add<HStoreNamedField>(bound_function, HObjectAccess::ForMap(),
    693                         bound_function_map);
    694   HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex);
    695   Add<HStoreNamedField>(bound_function, HObjectAccess::ForPropertiesPointer(),
    696                         empty_fixed_array);
    697   Add<HStoreNamedField>(bound_function, HObjectAccess::ForElementsPointer(),
    698                         empty_fixed_array);
    699   Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundTargetFunction(),
    700                         object);
    701 
    702   Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundThis(),
    703                         receiver);
    704   Add<HStoreNamedField>(bound_function, HObjectAccess::ForBoundArguments(),
    705                         elements);
    706 
    707   return bound_function;
    708 }
    709 
    710 Handle<Code> FastFunctionBindStub::GenerateCode() {
    711   return DoGenerateCode(this);
    712 }
    713 
    714 template <>
    715 HValue* CodeStubGraphBuilder<LoadFastElementStub>::BuildCodeStub() {
    716   LoadKeyedHoleMode hole_mode = casted_stub()->convert_hole_to_undefined()
    717                                     ? CONVERT_HOLE_TO_UNDEFINED
    718                                     : NEVER_RETURN_HOLE;
    719 
    720   HInstruction* load = BuildUncheckedMonomorphicElementAccess(
    721       GetParameter(Descriptor::kReceiver), GetParameter(Descriptor::kName),
    722       NULL, casted_stub()->is_js_array(), casted_stub()->elements_kind(), LOAD,
    723       hole_mode, STANDARD_STORE);
    724   return load;
    725 }
    726 
    727 
    728 Handle<Code> LoadFastElementStub::GenerateCode() {
    729   return DoGenerateCode(this);
    730 }
    731 
    732 
    733 HLoadNamedField* CodeStubGraphBuilderBase::BuildLoadNamedField(
    734     HValue* object, FieldIndex index) {
    735   Representation representation = index.is_double()
    736       ? Representation::Double()
    737       : Representation::Tagged();
    738   int offset = index.offset();
    739   HObjectAccess access = index.is_inobject()
    740       ? HObjectAccess::ForObservableJSObjectOffset(offset, representation)
    741       : HObjectAccess::ForBackingStoreOffset(offset, representation);
    742   if (index.is_double() &&
    743       (!FLAG_unbox_double_fields || !index.is_inobject())) {
    744     // Load the heap number.
    745     object = Add<HLoadNamedField>(
    746         object, nullptr, access.WithRepresentation(Representation::Tagged()));
    747     // Load the double value from it.
    748     access = HObjectAccess::ForHeapNumberValue();
    749   }
    750   return Add<HLoadNamedField>(object, nullptr, access);
    751 }
    752 
    753 
    754 template<>
    755 HValue* CodeStubGraphBuilder<LoadFieldStub>::BuildCodeStub() {
    756   return BuildLoadNamedField(GetParameter(Descriptor::kReceiver),
    757                              casted_stub()->index());
    758 }
    759 
    760 
    761 Handle<Code> LoadFieldStub::GenerateCode() {
    762   return DoGenerateCode(this);
    763 }
    764 
    765 
    766 template <>
    767 HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() {
    768   HValue* map = AddLoadMap(GetParameter(Descriptor::kReceiver), NULL);
    769   HObjectAccess descriptors_access = HObjectAccess::ForObservableJSObjectOffset(
    770       Map::kDescriptorsOffset, Representation::Tagged());
    771   HValue* descriptors = Add<HLoadNamedField>(map, nullptr, descriptors_access);
    772   HObjectAccess value_access = HObjectAccess::ForObservableJSObjectOffset(
    773       DescriptorArray::GetValueOffset(casted_stub()->constant_index()));
    774   return Add<HLoadNamedField>(descriptors, nullptr, value_access);
    775 }
    776 
    777 
    778 Handle<Code> LoadConstantStub::GenerateCode() { return DoGenerateCode(this); }
    779 
    780 
    781 void CodeStubGraphBuilderBase::BuildStoreNamedField(
    782     HValue* object, HValue* value, FieldIndex index,
    783     Representation representation, bool transition_to_field) {
    784   DCHECK(!index.is_double() || representation.IsDouble());
    785   int offset = index.offset();
    786   HObjectAccess access =
    787       index.is_inobject()
    788           ? HObjectAccess::ForObservableJSObjectOffset(offset, representation)
    789           : HObjectAccess::ForBackingStoreOffset(offset, representation);
    790 
    791   if (representation.IsDouble()) {
    792     if (!FLAG_unbox_double_fields || !index.is_inobject()) {
    793       HObjectAccess heap_number_access =
    794           access.WithRepresentation(Representation::Tagged());
    795       if (transition_to_field) {
    796         // The store requires a mutable HeapNumber to be allocated.
    797         NoObservableSideEffectsScope no_side_effects(this);
    798         HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize);
    799 
    800         // TODO(hpayer): Allocation site pretenuring support.
    801         HInstruction* heap_number =
    802             Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED,
    803                            MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0());
    804         AddStoreMapConstant(heap_number,
    805                             isolate()->factory()->mutable_heap_number_map());
    806         Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
    807                               value);
    808         // Store the new mutable heap number into the object.
    809         access = heap_number_access;
    810         value = heap_number;
    811       } else {
    812         // Load the heap number.
    813         object = Add<HLoadNamedField>(object, nullptr, heap_number_access);
    814         // Store the double value into it.
    815         access = HObjectAccess::ForHeapNumberValue();
    816       }
    817     }
    818   } else if (representation.IsHeapObject()) {
    819     BuildCheckHeapObject(value);
    820   }
    821 
    822   Add<HStoreNamedField>(object, access, value, INITIALIZING_STORE);
    823 }
    824 
    825 
    826 template <>
    827 HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
    828   ElementsKind const from_kind = casted_stub()->from_kind();
    829   ElementsKind const to_kind = casted_stub()->to_kind();
    830   HValue* const object = GetParameter(Descriptor::kObject);
    831   HValue* const map = GetParameter(Descriptor::kMap);
    832 
    833   // The {object} is known to be a JSObject (otherwise it wouldn't have elements
    834   // anyways).
    835   object->set_type(HType::JSObject());
    836 
    837   info()->MarkAsSavesCallerDoubles();
    838 
    839   DCHECK_IMPLIES(IsFastHoleyElementsKind(from_kind),
    840                  IsFastHoleyElementsKind(to_kind));
    841 
    842   if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) {
    843     Add<HTrapAllocationMemento>(object);
    844   }
    845 
    846   if (!IsSimpleMapChangeTransition(from_kind, to_kind)) {
    847     HInstruction* elements = AddLoadElements(object);
    848 
    849     IfBuilder if_objecthaselements(this);
    850     if_objecthaselements.IfNot<HCompareObjectEqAndBranch>(
    851         elements, Add<HConstant>(isolate()->factory()->empty_fixed_array()));
    852     if_objecthaselements.Then();
    853     {
    854       // Determine the elements capacity.
    855       HInstruction* elements_length = AddLoadFixedArrayLength(elements);
    856 
    857       // Determine the effective (array) length.
    858       IfBuilder if_objectisarray(this);
    859       if_objectisarray.If<HHasInstanceTypeAndBranch>(object, JS_ARRAY_TYPE);
    860       if_objectisarray.Then();
    861       {
    862         // The {object} is a JSArray, load the special "length" property.
    863         Push(Add<HLoadNamedField>(object, nullptr,
    864                                   HObjectAccess::ForArrayLength(from_kind)));
    865       }
    866       if_objectisarray.Else();
    867       {
    868         // The {object} is some other JSObject.
    869         Push(elements_length);
    870       }
    871       if_objectisarray.End();
    872       HValue* length = Pop();
    873 
    874       BuildGrowElementsCapacity(object, elements, from_kind, to_kind, length,
    875                                 elements_length);
    876     }
    877     if_objecthaselements.End();
    878   }
    879 
    880   Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map);
    881 
    882   return object;
    883 }
    884 
    885 
    886 Handle<Code> TransitionElementsKindStub::GenerateCode() {
    887   return DoGenerateCode(this);
    888 }
    889 
    890 template <>
    891 HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
    892   BinaryOpICState state = casted_stub()->state();
    893 
    894   HValue* left = GetParameter(Descriptor::kLeft);
    895   HValue* right = GetParameter(Descriptor::kRight);
    896 
    897   AstType* left_type = state.GetLeftType();
    898   AstType* right_type = state.GetRightType();
    899   AstType* result_type = state.GetResultType();
    900 
    901   DCHECK(!left_type->Is(AstType::None()) && !right_type->Is(AstType::None()) &&
    902          (state.HasSideEffects() || !result_type->Is(AstType::None())));
    903 
    904   HValue* result = NULL;
    905   HAllocationMode allocation_mode(NOT_TENURED);
    906   if (state.op() == Token::ADD && (left_type->Maybe(AstType::String()) ||
    907                                    right_type->Maybe(AstType::String())) &&
    908       !left_type->Is(AstType::String()) && !right_type->Is(AstType::String())) {
    909     // For the generic add stub a fast case for string addition is performance
    910     // critical.
    911     if (left_type->Maybe(AstType::String())) {
    912       IfBuilder if_leftisstring(this);
    913       if_leftisstring.If<HIsStringAndBranch>(left);
    914       if_leftisstring.Then();
    915       {
    916         Push(BuildBinaryOperation(state.op(), left, right, AstType::String(),
    917                                   right_type, result_type,
    918                                   state.fixed_right_arg(), allocation_mode));
    919       }
    920       if_leftisstring.Else();
    921       {
    922         Push(BuildBinaryOperation(state.op(), left, right, left_type,
    923                                   right_type, result_type,
    924                                   state.fixed_right_arg(), allocation_mode));
    925       }
    926       if_leftisstring.End();
    927       result = Pop();
    928     } else {
    929       IfBuilder if_rightisstring(this);
    930       if_rightisstring.If<HIsStringAndBranch>(right);
    931       if_rightisstring.Then();
    932       {
    933         Push(BuildBinaryOperation(state.op(), left, right, left_type,
    934                                   AstType::String(), result_type,
    935                                   state.fixed_right_arg(), allocation_mode));
    936       }
    937       if_rightisstring.Else();
    938       {
    939         Push(BuildBinaryOperation(state.op(), left, right, left_type,
    940                                   right_type, result_type,
    941                                   state.fixed_right_arg(), allocation_mode));
    942       }
    943       if_rightisstring.End();
    944       result = Pop();
    945     }
    946   } else {
    947     result = BuildBinaryOperation(state.op(), left, right, left_type,
    948                                   right_type, result_type,
    949                                   state.fixed_right_arg(), allocation_mode);
    950   }
    951 
    952   // If we encounter a generic argument, the number conversion is
    953   // observable, thus we cannot afford to bail out after the fact.
    954   if (!state.HasSideEffects()) {
    955     result = EnforceNumberType(result, result_type);
    956   }
    957 
    958   return result;
    959 }
    960 
    961 
    962 Handle<Code> BinaryOpICStub::GenerateCode() {
    963   return DoGenerateCode(this);
    964 }
    965 
    966 
    967 template <>
    968 HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() {
    969   BinaryOpICState state = casted_stub()->state();
    970 
    971   HValue* allocation_site = GetParameter(Descriptor::kAllocationSite);
    972   HValue* left = GetParameter(Descriptor::kLeft);
    973   HValue* right = GetParameter(Descriptor::kRight);
    974 
    975   AstType* left_type = state.GetLeftType();
    976   AstType* right_type = state.GetRightType();
    977   AstType* result_type = state.GetResultType();
    978   HAllocationMode allocation_mode(allocation_site);
    979 
    980   return BuildBinaryOperation(state.op(), left, right, left_type, right_type,
    981                               result_type, state.fixed_right_arg(),
    982                               allocation_mode);
    983 }
    984 
    985 
    986 Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode() {
    987   return DoGenerateCode(this);
    988 }
    989 
    990 
    991 HValue* CodeStubGraphBuilderBase::BuildToString(HValue* input, bool convert) {
    992   if (!convert) return BuildCheckString(input);
    993   IfBuilder if_inputissmi(this);
    994   HValue* inputissmi = if_inputissmi.If<HIsSmiAndBranch>(input);
    995   if_inputissmi.Then();
    996   {
    997     // Convert the input smi to a string.
    998     Push(BuildNumberToString(input, AstType::SignedSmall()));
    999   }
   1000   if_inputissmi.Else();
   1001   {
   1002     HValue* input_map =
   1003         Add<HLoadNamedField>(input, inputissmi, HObjectAccess::ForMap());
   1004     HValue* input_instance_type = Add<HLoadNamedField>(
   1005         input_map, inputissmi, HObjectAccess::ForMapInstanceType());
   1006     IfBuilder if_inputisstring(this);
   1007     if_inputisstring.If<HCompareNumericAndBranch>(
   1008         input_instance_type, Add<HConstant>(FIRST_NONSTRING_TYPE), Token::LT);
   1009     if_inputisstring.Then();
   1010     {
   1011       // The input is already a string.
   1012       Push(input);
   1013     }
   1014     if_inputisstring.Else();
   1015     {
   1016       // Convert to primitive first (if necessary), see
   1017       // ES6 section 12.7.3 The Addition operator.
   1018       IfBuilder if_inputisprimitive(this);
   1019       STATIC_ASSERT(FIRST_PRIMITIVE_TYPE == FIRST_TYPE);
   1020       if_inputisprimitive.If<HCompareNumericAndBranch>(
   1021           input_instance_type, Add<HConstant>(LAST_PRIMITIVE_TYPE), Token::LTE);
   1022       if_inputisprimitive.Then();
   1023       {
   1024         // The input is already a primitive.
   1025         Push(input);
   1026       }
   1027       if_inputisprimitive.Else();
   1028       {
   1029         // Convert the input to a primitive.
   1030         Push(BuildToPrimitive(input, input_map));
   1031       }
   1032       if_inputisprimitive.End();
   1033       // Convert the primitive to a string value.
   1034       HValue* values[] = {Pop()};
   1035       Callable toString = CodeFactory::ToString(isolate());
   1036       Push(AddUncasted<HCallWithDescriptor>(Add<HConstant>(toString.code()), 0,
   1037                                             toString.descriptor(),
   1038                                             ArrayVector(values)));
   1039     }
   1040     if_inputisstring.End();
   1041   }
   1042   if_inputissmi.End();
   1043   return Pop();
   1044 }
   1045 
   1046 
   1047 HValue* CodeStubGraphBuilderBase::BuildToPrimitive(HValue* input,
   1048                                                    HValue* input_map) {
   1049   // Get the native context of the caller.
   1050   HValue* native_context = BuildGetNativeContext();
   1051 
   1052   // Determine the initial map of the %ObjectPrototype%.
   1053   HValue* object_function_prototype_map =
   1054       Add<HLoadNamedField>(native_context, nullptr,
   1055                            HObjectAccess::ForContextSlot(
   1056                                Context::OBJECT_FUNCTION_PROTOTYPE_MAP_INDEX));
   1057 
   1058   // Determine the initial map of the %StringPrototype%.
   1059   HValue* string_function_prototype_map =
   1060       Add<HLoadNamedField>(native_context, nullptr,
   1061                            HObjectAccess::ForContextSlot(
   1062                                Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
   1063 
   1064   // Determine the initial map of the String function.
   1065   HValue* string_function = Add<HLoadNamedField>(
   1066       native_context, nullptr,
   1067       HObjectAccess::ForContextSlot(Context::STRING_FUNCTION_INDEX));
   1068   HValue* string_function_initial_map = Add<HLoadNamedField>(
   1069       string_function, nullptr, HObjectAccess::ForPrototypeOrInitialMap());
   1070 
   1071   // Determine the map of the [[Prototype]] of {input}.
   1072   HValue* input_prototype =
   1073       Add<HLoadNamedField>(input_map, nullptr, HObjectAccess::ForPrototype());
   1074   HValue* input_prototype_map =
   1075       Add<HLoadNamedField>(input_prototype, nullptr, HObjectAccess::ForMap());
   1076 
   1077   // For string wrappers (JSValue instances with [[StringData]] internal
   1078   // fields), we can shortcirciut the ToPrimitive if
   1079   //
   1080   //  (a) the {input} map matches the initial map of the String function,
   1081   //  (b) the {input} [[Prototype]] is the unmodified %StringPrototype% (i.e.
   1082   //      no one monkey-patched toString, @@toPrimitive or valueOf), and
   1083   //  (c) the %ObjectPrototype% (i.e. the [[Prototype]] of the
   1084   //      %StringPrototype%) is also unmodified, that is no one sneaked a
   1085   //      @@toPrimitive into the %ObjectPrototype%.
   1086   //
   1087   // If all these assumptions hold, we can just take the [[StringData]] value
   1088   // and return it.
   1089   // TODO(bmeurer): This just repairs a regression introduced by removing the
   1090   // weird (and broken) intrinsic %_IsStringWrapperSafeForDefaultValue, which
   1091   // was intendend to something similar to this, although less efficient and
   1092   // wrong in the presence of @@toPrimitive. Long-term we might want to move
   1093   // into the direction of having a ToPrimitiveStub that can do common cases
   1094   // while staying in JavaScript land (i.e. not going to C++).
   1095   IfBuilder if_inputisstringwrapper(this);
   1096   if_inputisstringwrapper.If<HCompareObjectEqAndBranch>(
   1097       input_map, string_function_initial_map);
   1098   if_inputisstringwrapper.And();
   1099   if_inputisstringwrapper.If<HCompareObjectEqAndBranch>(
   1100       input_prototype_map, string_function_prototype_map);
   1101   if_inputisstringwrapper.And();
   1102   if_inputisstringwrapper.If<HCompareObjectEqAndBranch>(
   1103       Add<HLoadNamedField>(Add<HLoadNamedField>(input_prototype_map, nullptr,
   1104                                                 HObjectAccess::ForPrototype()),
   1105                            nullptr, HObjectAccess::ForMap()),
   1106       object_function_prototype_map);
   1107   if_inputisstringwrapper.Then();
   1108   {
   1109     Push(BuildLoadNamedField(
   1110         input, FieldIndex::ForInObjectOffset(JSValue::kValueOffset)));
   1111   }
   1112   if_inputisstringwrapper.Else();
   1113   {
   1114     // TODO(bmeurer): Add support for fast ToPrimitive conversion using
   1115     // a dedicated ToPrimitiveStub.
   1116     Add<HPushArguments>(input);
   1117     Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kToPrimitive), 1));
   1118   }
   1119   if_inputisstringwrapper.End();
   1120   return Pop();
   1121 }
   1122 
   1123 template <>
   1124 HValue* CodeStubGraphBuilder<ToBooleanICStub>::BuildCodeInitializedStub() {
   1125   ToBooleanICStub* stub = casted_stub();
   1126   IfBuilder if_true(this);
   1127   if_true.If<HBranch>(GetParameter(Descriptor::kArgument), stub->hints());
   1128   if_true.Then();
   1129   if_true.Return(graph()->GetConstantTrue());
   1130   if_true.Else();
   1131   if_true.End();
   1132   return graph()->GetConstantFalse();
   1133 }
   1134 
   1135 Handle<Code> ToBooleanICStub::GenerateCode() { return DoGenerateCode(this); }
   1136 
   1137 template <>
   1138 HValue* CodeStubGraphBuilder<LoadDictionaryElementStub>::BuildCodeStub() {
   1139   HValue* receiver = GetParameter(Descriptor::kReceiver);
   1140   HValue* key = GetParameter(Descriptor::kName);
   1141 
   1142   Add<HCheckSmi>(key);
   1143 
   1144   HValue* elements = AddLoadElements(receiver);
   1145 
   1146   HValue* hash = BuildElementIndexHash(key);
   1147 
   1148   return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash);
   1149 }
   1150 
   1151 
   1152 Handle<Code> LoadDictionaryElementStub::GenerateCode() {
   1153   return DoGenerateCode(this);
   1154 }
   1155 
   1156 }  // namespace internal
   1157 }  // namespace v8
   1158