Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(635)

Unified Diff: src/ic/accessor-assembler.cc

Issue 2654893003: [stubs] KeyedLoadGeneric: support loading properties from strings (Closed)
Patch Set: fix typo in CSA_ASSERT Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/ic/accessor-assembler.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « src/ic/accessor-assembler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698