| Index: src/ic/accessor-assembler.cc | 
| diff --git a/src/ic/accessor-assembler.cc b/src/ic/accessor-assembler.cc | 
| index 447258a509c43a97a45b1b929ba2b0b0b030eb74..1cb23279538bb854dd6b0c4d477bef24db39bb51 100644 | 
| --- a/src/ic/accessor-assembler.cc | 
| +++ b/src/ic/accessor-assembler.cc | 
| @@ -1098,6 +1098,222 @@ void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name, | 
| Bind(&done); | 
| } | 
|  | 
| +void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map, | 
| +                                           Node* instance_type, Node* index, | 
| +                                           Label* slow) { | 
| +  Comment("integer index"); | 
| +  Label if_element_hole(this), if_oob(this); | 
| +  // Receivers requiring non-standard element accesses (interceptors, access | 
| +  // checks, strings and string wrappers, proxies) are handled in the runtime. | 
| +  GotoIf(Int32LessThanOrEqual(instance_type, | 
| +                              Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), | 
| +         slow); | 
| +  Node* elements = LoadElements(receiver); | 
| +  Node* elements_kind = LoadMapElementsKind(receiver_map); | 
| +  Node* is_jsarray_condition = | 
| +      Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)); | 
| +  Variable var_double_value(this, MachineRepresentation::kFloat64); | 
| +  Label rebox_double(this, &var_double_value); | 
| + | 
| +  // Unimplemented elements kinds fall back to a runtime call. | 
| +  Label* unimplemented_elements_kind = slow; | 
| +  IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1); | 
| +  EmitElementLoad(receiver, elements, elements_kind, index, | 
| +                  is_jsarray_condition, &if_element_hole, &rebox_double, | 
| +                  &var_double_value, unimplemented_elements_kind, &if_oob, | 
| +                  slow); | 
| + | 
| +  Bind(&rebox_double); | 
| +  Return(AllocateHeapNumberWithValue(var_double_value.value())); | 
| + | 
| +  Bind(&if_oob); | 
| +  { | 
| +    Comment("out of bounds"); | 
| +    // Negative keys can't take the fast OOB path. | 
| +    GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), slow); | 
| +    // Positive OOB indices are effectively the same as hole loads. | 
| +    Goto(&if_element_hole); | 
| +  } | 
| + | 
| +  Bind(&if_element_hole); | 
| +  { | 
| +    Comment("found the hole"); | 
| +    Label return_undefined(this); | 
| +    BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow); | 
| + | 
| +    Bind(&return_undefined); | 
| +    Return(UndefinedConstant()); | 
| +  } | 
| +} | 
| + | 
| +void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, | 
| +                                            Node* instance_type, Node* key, | 
| +                                            const LoadICParameters* p, | 
| +                                            Label* slow) { | 
| +  Comment("key is unique name"); | 
| +  Label if_found_on_receiver(this), if_property_dictionary(this), | 
| +      lookup_prototype_chain(this); | 
| +  Variable var_details(this, MachineRepresentation::kWord32); | 
| +  Variable var_value(this, MachineRepresentation::kTagged); | 
| + | 
| +  // Receivers requiring non-standard accesses (interceptors, access | 
| +  // checks, string wrappers, proxies) are handled in the runtime. | 
| +  // We special-case strings here, to support loading <Symbol.split> etc. | 
| +  Variable var_receiver(this, MachineRepresentation::kTagged); | 
| +  Variable var_receiver_map(this, MachineRepresentation::kTagged); | 
| +  Variable var_instance_type(this, MachineRepresentation::kWord32); | 
| +  var_receiver.Bind(receiver); | 
| +  var_receiver_map.Bind(receiver_map); | 
| +  var_instance_type.Bind(instance_type); | 
| +  Label normal_receiver(this); | 
| +  GotoIf(Int32GreaterThan(instance_type, | 
| +                          Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)), | 
| +         &normal_receiver); | 
| +  GotoIf(Int32GreaterThanOrEqual(instance_type, | 
| +                                 Int32Constant(FIRST_NONSTRING_TYPE)), | 
| +         slow); | 
| +  CSA_ASSERT(this, WordEqual(LoadMapConstructorFunctionIndex(receiver_map), | 
| +                             IntPtrConstant(Context::STRING_FUNCTION_INDEX))); | 
| +  Node* native_context = LoadNativeContext(p->context); | 
| +  Node* constructor_function = | 
| +      LoadContextElement(native_context, Context::STRING_FUNCTION_INDEX); | 
| +  Node* initial_map = LoadObjectField(constructor_function, | 
| +                                      JSFunction::kPrototypeOrInitialMapOffset); | 
| +  var_receiver.Bind(LoadMapPrototype(initial_map)); | 
| +  var_receiver_map.Bind(LoadMap(var_receiver.value())); | 
| +  var_instance_type.Bind(LoadMapInstanceType(var_receiver_map.value())); | 
| +  Goto(&normal_receiver); | 
| + | 
| +  Bind(&normal_receiver); | 
| +  receiver = var_receiver.value(); | 
| +  receiver_map = var_receiver_map.value(); | 
| +  instance_type = var_instance_type.value(); | 
| +  // Check if the receiver has fast or slow properties. | 
| +  Node* properties = LoadProperties(receiver); | 
| +  Node* properties_map = LoadMap(properties); | 
| +  GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), | 
| +         &if_property_dictionary); | 
| + | 
| +  // Try looking up the property on the receiver; if unsuccessful, look | 
| +  // for a handler in the stub cache. | 
| +  Comment("DescriptorArray lookup"); | 
| + | 
| +  // Skip linear search if there are too many descriptors. | 
| +  // TODO(jkummerow): Consider implementing binary search. | 
| +  // See also TryLookupProperty() which has the same limitation. | 
| +  const int32_t kMaxLinear = 210; | 
| +  Label stub_cache(this); | 
| +  Node* bitfield3 = LoadMapBitField3(var_receiver_map.value()); | 
| +  Node* nof = DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3); | 
| +  GotoIf(UintPtrLessThan(IntPtrConstant(kMaxLinear), nof), &stub_cache); | 
| +  Node* descriptors = LoadMapDescriptors(var_receiver_map.value()); | 
| +  Variable var_name_index(this, MachineType::PointerRepresentation()); | 
| +  Label if_descriptor_found(this); | 
| +  DescriptorLookupLinear(key, descriptors, nof, &if_descriptor_found, | 
| +                         &var_name_index, &stub_cache); | 
| + | 
| +  Bind(&if_descriptor_found); | 
| +  { | 
| +    LoadPropertyFromFastObject(receiver, var_receiver_map.value(), descriptors, | 
| +                               var_name_index.value(), &var_details, | 
| +                               &var_value); | 
| +    Goto(&if_found_on_receiver); | 
| +  } | 
| + | 
| +  Bind(&stub_cache); | 
| +  { | 
| +    Comment("stub cache probe for fast property load"); | 
| +    Variable var_handler(this, MachineRepresentation::kTagged); | 
| +    Label found_handler(this, &var_handler), stub_cache_miss(this); | 
| +    TryProbeStubCache(isolate()->load_stub_cache(), receiver, key, | 
| +                      &found_handler, &var_handler, &stub_cache_miss); | 
| +    Bind(&found_handler); | 
| +    { HandleLoadICHandlerCase(p, var_handler.value(), slow); } | 
| + | 
| +    Bind(&stub_cache_miss); | 
| +    { | 
| +      // TODO(jkummerow): Check if the property exists on the prototype | 
| +      // chain. If it doesn't, then there's no point in missing. | 
| +      Comment("KeyedLoadGeneric_miss"); | 
| +      TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, | 
| +                      p->name, p->slot, p->vector); | 
| +    } | 
| +  } | 
| + | 
| +  Bind(&if_property_dictionary); | 
| +  { | 
| +    Comment("dictionary property load"); | 
| +    // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out | 
| +    // seeing global objects here (which would need special handling). | 
| + | 
| +    Variable var_name_index(this, MachineType::PointerRepresentation()); | 
| +    Label dictionary_found(this, &var_name_index); | 
| +    NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found, | 
| +                                         &var_name_index, | 
| +                                         &lookup_prototype_chain); | 
| +    Bind(&dictionary_found); | 
| +    { | 
| +      LoadPropertyFromNameDictionary(properties, var_name_index.value(), | 
| +                                     &var_details, &var_value); | 
| +      Goto(&if_found_on_receiver); | 
| +    } | 
| +  } | 
| + | 
| +  Bind(&if_found_on_receiver); | 
| +  { | 
| +    Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(), | 
| +                                       p->context, var_receiver.value(), slow); | 
| +    IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1); | 
| +    Return(value); | 
| +  } | 
| + | 
| +  Bind(&lookup_prototype_chain); | 
| +  { | 
| +    Variable var_holder_map(this, MachineRepresentation::kTagged); | 
| +    Variable var_holder_instance_type(this, MachineRepresentation::kWord32); | 
| +    Label return_undefined(this); | 
| +    Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type}; | 
| +    Label loop(this, arraysize(merged_variables), merged_variables); | 
| + | 
| +    var_holder_map.Bind(var_receiver_map.value()); | 
| +    var_holder_instance_type.Bind(var_instance_type.value()); | 
| +    // Private symbols must not be looked up on the prototype chain. | 
| +    GotoIf(IsPrivateSymbol(key), &return_undefined); | 
| +    Goto(&loop); | 
| +    Bind(&loop); | 
| +    { | 
| +      // Bailout if it can be an integer indexed exotic case. | 
| +      GotoIf(Word32Equal(var_holder_instance_type.value(), | 
| +                         Int32Constant(JS_TYPED_ARRAY_TYPE)), | 
| +             slow); | 
| +      Node* proto = LoadMapPrototype(var_holder_map.value()); | 
| +      GotoIf(WordEqual(proto, NullConstant()), &return_undefined); | 
| +      Node* proto_map = LoadMap(proto); | 
| +      Node* proto_instance_type = LoadMapInstanceType(proto_map); | 
| +      var_holder_map.Bind(proto_map); | 
| +      var_holder_instance_type.Bind(proto_instance_type); | 
| +      Label next_proto(this), return_value(this, &var_value), goto_slow(this); | 
| +      TryGetOwnProperty(p->context, var_receiver.value(), proto, proto_map, | 
| +                        proto_instance_type, key, &return_value, &var_value, | 
| +                        &next_proto, &goto_slow); | 
| + | 
| +      // This trampoline and the next are required to appease Turbofan's | 
| +      // variable merging. | 
| +      Bind(&next_proto); | 
| +      Goto(&loop); | 
| + | 
| +      Bind(&goto_slow); | 
| +      Goto(slow); | 
| + | 
| +      Bind(&return_value); | 
| +      Return(var_value.value()); | 
| +    } | 
| + | 
| +    Bind(&return_undefined); | 
| +    Return(UndefinedConstant()); | 
| +  } | 
| +} | 
| + | 
| //////////////////// Stub cache access helpers. | 
|  | 
| enum AccessorAssembler::StubCacheTable : int { | 
| @@ -1399,198 +1615,26 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) { | 
| Variable var_index(this, MachineType::PointerRepresentation()); | 
| Variable var_unique(this, MachineRepresentation::kTagged); | 
| var_unique.Bind(p->name);  // Dummy initialization. | 
| -  Variable var_details(this, MachineRepresentation::kWord32); | 
| -  Variable var_value(this, MachineRepresentation::kTagged); | 
| -  Label if_index(this), if_unique_name(this), if_element_hole(this), | 
| -      if_oob(this), slow(this), stub_cache_miss(this), | 
| -      if_property_dictionary(this), if_found_on_receiver(this), | 
| -      lookup_prototype_chain(this); | 
| +  Label if_index(this), if_unique_name(this), slow(this); | 
|  | 
| Node* receiver = p->receiver; | 
| GotoIf(TaggedIsSmi(receiver), &slow); | 
| Node* receiver_map = LoadMap(receiver); | 
| Node* instance_type = LoadMapInstanceType(receiver_map); | 
| -  // Receivers requiring non-standard element accesses (interceptors, access | 
| -  // checks, strings and string wrappers, proxies) are handled in the runtime. | 
| -  GotoIf(Int32LessThanOrEqual(instance_type, | 
| -                              Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)), | 
| -         &slow); | 
|  | 
| TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique, | 
| &slow); | 
|  | 
| Bind(&if_index); | 
| { | 
| -    Comment("integer index"); | 
| -    Node* index = var_index.value(); | 
| -    Node* elements = LoadElements(receiver); | 
| -    Node* elements_kind = LoadMapElementsKind(receiver_map); | 
| -    Node* is_jsarray_condition = | 
| -        Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)); | 
| -    Variable var_double_value(this, MachineRepresentation::kFloat64); | 
| -    Label rebox_double(this, &var_double_value); | 
| - | 
| -    // Unimplemented elements kinds fall back to a runtime call. | 
| -    Label* unimplemented_elements_kind = &slow; | 
| -    IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1); | 
| -    EmitElementLoad(receiver, elements, elements_kind, index, | 
| -                    is_jsarray_condition, &if_element_hole, &rebox_double, | 
| -                    &var_double_value, unimplemented_elements_kind, &if_oob, | 
| -                    &slow); | 
| - | 
| -    Bind(&rebox_double); | 
| -    Return(AllocateHeapNumberWithValue(var_double_value.value())); | 
| +    GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(), | 
| +                       &slow); | 
| } | 
|  | 
| -  Bind(&if_oob); | 
| -  { | 
| -    Comment("out of bounds"); | 
| -    Node* index = var_index.value(); | 
| -    // Negative keys can't take the fast OOB path. | 
| -    GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), &slow); | 
| -    // Positive OOB indices are effectively the same as hole loads. | 
| -    Goto(&if_element_hole); | 
| -  } | 
| - | 
| -  Bind(&if_element_hole); | 
| -  { | 
| -    Comment("found the hole"); | 
| -    Label return_undefined(this); | 
| -    BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, &slow); | 
| - | 
| -    Bind(&return_undefined); | 
| -    Return(UndefinedConstant()); | 
| -  } | 
| - | 
| -  Node* properties = nullptr; | 
| Bind(&if_unique_name); | 
| { | 
| -    Comment("key is unique name"); | 
| -    Node* key = var_unique.value(); | 
| -    // Check if the receiver has fast or slow properties. | 
| -    properties = LoadProperties(receiver); | 
| -    Node* properties_map = LoadMap(properties); | 
| -    GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), | 
| -           &if_property_dictionary); | 
| - | 
| -    // Try looking up the property on the receiver; if unsuccessful, look | 
| -    // for a handler in the stub cache. | 
| -    Comment("DescriptorArray lookup"); | 
| - | 
| -    // Skip linear search if there are too many descriptors. | 
| -    // TODO(jkummerow): Consider implementing binary search. | 
| -    // See also TryLookupProperty() which has the same limitation. | 
| -    const int32_t kMaxLinear = 210; | 
| -    Label stub_cache(this); | 
| -    Node* bitfield3 = LoadMapBitField3(receiver_map); | 
| -    Node* nof = | 
| -        DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3); | 
| -    GotoIf(UintPtrLessThan(IntPtrConstant(kMaxLinear), nof), &stub_cache); | 
| -    Node* descriptors = LoadMapDescriptors(receiver_map); | 
| -    Variable var_name_index(this, MachineType::PointerRepresentation()); | 
| -    Label if_descriptor_found(this); | 
| -    DescriptorLookupLinear(key, descriptors, nof, &if_descriptor_found, | 
| -                           &var_name_index, &stub_cache); | 
| - | 
| -    Bind(&if_descriptor_found); | 
| -    { | 
| -      LoadPropertyFromFastObject(receiver, receiver_map, descriptors, | 
| -                                 var_name_index.value(), &var_details, | 
| -                                 &var_value); | 
| -      Goto(&if_found_on_receiver); | 
| -    } | 
| - | 
| -    Bind(&stub_cache); | 
| -    { | 
| -      Comment("stub cache probe for fast property load"); | 
| -      Variable var_handler(this, MachineRepresentation::kTagged); | 
| -      Label found_handler(this, &var_handler), stub_cache_miss(this); | 
| -      TryProbeStubCache(isolate()->load_stub_cache(), receiver, key, | 
| -                        &found_handler, &var_handler, &stub_cache_miss); | 
| -      Bind(&found_handler); | 
| -      { HandleLoadICHandlerCase(p, var_handler.value(), &slow); } | 
| - | 
| -      Bind(&stub_cache_miss); | 
| -      { | 
| -        Comment("KeyedLoadGeneric_miss"); | 
| -        TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, | 
| -                        p->name, p->slot, p->vector); | 
| -      } | 
| -    } | 
| -  } | 
| - | 
| -  Bind(&if_property_dictionary); | 
| -  { | 
| -    Comment("dictionary property load"); | 
| -    // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out | 
| -    // seeing global objects here (which would need special handling). | 
| - | 
| -    Node* key = var_unique.value(); | 
| -    Variable var_name_index(this, MachineType::PointerRepresentation()); | 
| -    Label dictionary_found(this, &var_name_index); | 
| -    NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found, | 
| -                                         &var_name_index, | 
| -                                         &lookup_prototype_chain); | 
| -    Bind(&dictionary_found); | 
| -    { | 
| -      LoadPropertyFromNameDictionary(properties, var_name_index.value(), | 
| -                                     &var_details, &var_value); | 
| -      Goto(&if_found_on_receiver); | 
| -    } | 
| -  } | 
| - | 
| -  Bind(&if_found_on_receiver); | 
| -  { | 
| -    Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(), | 
| -                                       p->context, receiver, &slow); | 
| -    IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1); | 
| -    Return(value); | 
| -  } | 
| - | 
| -  Bind(&lookup_prototype_chain); | 
| -  { | 
| -    Variable var_holder_map(this, MachineRepresentation::kTagged); | 
| -    Variable var_holder_instance_type(this, MachineRepresentation::kWord32); | 
| -    Label return_undefined(this); | 
| -    Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type}; | 
| -    Label loop(this, arraysize(merged_variables), merged_variables); | 
| - | 
| -    var_holder_map.Bind(receiver_map); | 
| -    var_holder_instance_type.Bind(instance_type); | 
| -    // Private symbols must not be looked up on the prototype chain. | 
| -    GotoIf(IsPrivateSymbol(var_unique.value()), &return_undefined); | 
| -    Goto(&loop); | 
| -    Bind(&loop); | 
| -    { | 
| -      // Bailout if it can be an integer indexed exotic case. | 
| -      GotoIf(Word32Equal(var_holder_instance_type.value(), | 
| -                         Int32Constant(JS_TYPED_ARRAY_TYPE)), | 
| -             &slow); | 
| -      Node* proto = LoadMapPrototype(var_holder_map.value()); | 
| -      GotoIf(WordEqual(proto, NullConstant()), &return_undefined); | 
| -      Node* proto_map = LoadMap(proto); | 
| -      Node* proto_instance_type = LoadMapInstanceType(proto_map); | 
| -      var_holder_map.Bind(proto_map); | 
| -      var_holder_instance_type.Bind(proto_instance_type); | 
| -      Label next_proto(this), return_value(this, &var_value), goto_slow(this); | 
| -      TryGetOwnProperty(p->context, receiver, proto, proto_map, | 
| -                        proto_instance_type, var_unique.value(), &return_value, | 
| -                        &var_value, &next_proto, &goto_slow); | 
| - | 
| -      // This trampoline and the next are required to appease Turbofan's | 
| -      // variable merging. | 
| -      Bind(&next_proto); | 
| -      Goto(&loop); | 
| - | 
| -      Bind(&goto_slow); | 
| -      Goto(&slow); | 
| - | 
| -      Bind(&return_value); | 
| -      Return(var_value.value()); | 
| -    } | 
| - | 
| -    Bind(&return_undefined); | 
| -    Return(UndefinedConstant()); | 
| +    GenericPropertyLoad(receiver, receiver_map, instance_type, | 
| +                        var_unique.value(), p, &slow); | 
| } | 
|  | 
| Bind(&slow); | 
|  |