Chromium Code Reviews| Index: src/code-stubs-hydrogen.cc |
| diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc |
| index 88e71faca9ee9dca4db2991d81117fbb8568a147..564b2e6dff9f3b352f9a3d3e57e95ce592ea741c 100644 |
| --- a/src/code-stubs-hydrogen.cc |
| +++ b/src/code-stubs-hydrogen.cc |
| @@ -1390,7 +1390,11 @@ HValue* CodeStubGraphBuilder<KeyedLoadDictionaryElementStub>::BuildCodeStub() { |
| Add<HCheckSmi>(key); |
| - return BuildUncheckedDictionaryElementLoad(receiver, key); |
| + HValue* elements = AddLoadElements(receiver); |
| + |
| + HValue* hash = BuildElementIndexHash(key); |
| + |
| + return BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash); |
| } |
| @@ -1417,4 +1421,303 @@ Handle<Code> RegExpConstructResultStub::GenerateCode() { |
| } |
| +template <> |
| +class CodeStubGraphBuilder<KeyedLoadGenericElementStub> |
| + : public CodeStubGraphBuilderBase { |
| + public: |
| + CodeStubGraphBuilder(Isolate* isolate, |
| + KeyedLoadGenericElementStub* stub) |
| + : CodeStubGraphBuilderBase(isolate, stub) {} |
| + |
| + protected: |
| + virtual HValue* BuildCodeStub(); |
| + |
| + void BuildElementsKindLimitCheck(HGraphBuilder::IfBuilder* if_builder, |
| + HValue* bit_field2, |
| + ElementsKind kind); |
| + |
| + void BuildFastElementLoad(HGraphBuilder::IfBuilder* if_builder, |
| + HValue* receiver, |
| + HValue* key, |
| + HValue* instance_type, |
| + HValue* bit_field2, |
| + ElementsKind kind); |
| + |
| + void BuildExternalElementLoad(HGraphBuilder::IfBuilder* if_builder, |
| + HValue* receiver, |
| + HValue* key, |
| + HValue* instance_type, |
| + HValue* bit_field2, |
| + ElementsKind kind); |
| + |
| + KeyedLoadGenericElementStub* casted_stub() { |
| + return static_cast<KeyedLoadGenericElementStub*>(stub()); |
| + } |
| +}; |
| + |
| + |
| +void CodeStubGraphBuilder< |
| + KeyedLoadGenericElementStub>::BuildElementsKindLimitCheck( |
| + HGraphBuilder::IfBuilder* if_builder, |
| + HValue* bit_field2, |
| + ElementsKind kind) { |
| + ElementsKind next_kind = static_cast<ElementsKind>(kind + 1); |
| + HValue* kind_limit = Add<HConstant>( |
| + static_cast<int>(Map::ElementsKindBits::encode(next_kind))); |
| + |
| + if_builder->If<HCompareNumericAndBranch>(bit_field2, kind_limit, Token::LT); |
| + if_builder->Then(); |
| +} |
| + |
| + |
| +void CodeStubGraphBuilder<KeyedLoadGenericElementStub>::BuildFastElementLoad( |
| + HGraphBuilder::IfBuilder* if_builder, |
| + HValue* receiver, |
| + HValue* key, |
| + HValue* instance_type, |
| + HValue* bit_field2, |
| + ElementsKind kind) { |
| + ASSERT(!IsExternalArrayElementsKind(kind)); |
| + |
| + BuildElementsKindLimitCheck(if_builder, bit_field2, kind); |
| + |
| + IfBuilder js_array_check(this); |
| + js_array_check.If<HCompareNumericAndBranch>( |
| + instance_type, Add<HConstant>(JS_ARRAY_TYPE), Token::EQ); |
| + js_array_check.Then(); |
| + Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, |
| + true, kind, |
| + LOAD, NEVER_RETURN_HOLE, |
| + STANDARD_STORE)); |
| + js_array_check.Else(); |
| + Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, |
| + false, kind, |
| + LOAD, NEVER_RETURN_HOLE, |
| + STANDARD_STORE)); |
| + js_array_check.End(); |
| +} |
| + |
| + |
| +void CodeStubGraphBuilder< |
| + KeyedLoadGenericElementStub>::BuildExternalElementLoad( |
| + HGraphBuilder::IfBuilder* if_builder, |
| + HValue* receiver, |
| + HValue* key, |
| + HValue* instance_type, |
| + HValue* bit_field2, |
| + ElementsKind kind) { |
| + ASSERT(IsExternalArrayElementsKind(kind)); |
| + |
| + BuildElementsKindLimitCheck(if_builder, bit_field2, kind); |
| + |
| + Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, |
| + false, kind, |
| + LOAD, NEVER_RETURN_HOLE, |
| + STANDARD_STORE)); |
| +} |
| + |
| + |
| +HValue* CodeStubGraphBuilder<KeyedLoadGenericElementStub>::BuildCodeStub() { |
| + HValue* receiver = GetParameter(0); |
| + HValue* key = GetParameter(1); |
| + |
| + // Split into a smi/integer case and unique string case. |
| + HIfContinuation index_name_split_continuation(graph()->CreateBasicBlock(), |
| + graph()->CreateBasicBlock()); |
| + |
| + BuildKeyedIndexCheck(key, &index_name_split_continuation); |
| + |
| + IfBuilder index_name_split(this, &index_name_split_continuation); |
| + index_name_split.Then(); |
| + { |
| + // Key is an index (number) |
| + key = Pop(); |
| + |
| + int bit_field_mask = (1 << Map::kIsAccessCheckNeeded) | |
| + (1 << Map::kHasIndexedInterceptor); |
| + BuildReceiverCheck(receiver, bit_field_mask); |
| + |
| + HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL), |
| + HObjectAccess::ForMap()); |
| + |
| + HValue* instance_type = |
| + Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), |
| + HObjectAccess::ForMapInstanceType()); |
| + |
| + HValue* bit_field2 = Add<HLoadNamedField>(map, |
| + static_cast<HValue*>(NULL), |
| + HObjectAccess::ForMapBitField2()); |
| + |
| + IfBuilder kind_if(this); |
| + BuildFastElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + FAST_HOLEY_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + { |
| + BuildFastElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + FAST_HOLEY_DOUBLE_ELEMENTS); |
| + } |
| + kind_if.Else(); |
| + |
| + // The DICTIONARY_ELEMENTS check generates a "kind_if.Then" |
| + BuildElementsKindLimitCheck(&kind_if, bit_field2, DICTIONARY_ELEMENTS); |
| + { |
| + HValue* elements = AddLoadElements(receiver); |
| + |
| + HValue* hash = BuildElementIndexHash(key); |
| + |
| + Push(BuildUncheckedDictionaryElementLoad(receiver, elements, key, hash)); |
| + } |
| + kind_if.Else(); |
| + |
| + // The SLOPPY_ARGUMENTS_ELEMENTS check generates a "kind_if.Then" |
| + BuildElementsKindLimitCheck(&kind_if, bit_field2, |
| + SLOPPY_ARGUMENTS_ELEMENTS); |
| + // Non-strict elements are not handled. |
| + Add<HDeoptimize>("non-strict elements in KeyedLoadGenericElementStub", |
| + Deoptimizer::EAGER); |
| + Push(graph()->GetConstant0()); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_INT8_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_UINT8_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_INT16_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_UINT16_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_INT32_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_UINT32_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_FLOAT32_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_FLOAT64_ELEMENTS); |
| + |
| + kind_if.Else(); |
| + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, |
| + EXTERNAL_UINT8_CLAMPED_ELEMENTS); |
| + |
| + kind_if.ElseDeopt("ElementsKind unhandled in KeyedLoadGenericElementStub"); |
| + |
| + kind_if.End(); |
| + } |
| + index_name_split.Else(); |
| + { |
| + // Key is a unique string. |
| + key = Pop(); |
| + |
| + int bit_field_mask = (1 << Map::kIsAccessCheckNeeded) | |
| + (1 << Map::kHasNamedInterceptor); |
| + BuildReceiverCheck(receiver, bit_field_mask); |
|
Toon Verwaest
2014/06/10 11:33:43
Any reason why you don't put this outside of the i
Toon Verwaest
2014/06/10 11:37:07
Aarg, you already indicated this in the comments o
|
| + |
| + HIfContinuation continuation; |
| + BuildCheckForDictionaryProperties(receiver, &continuation); |
| + IfBuilder if_dict_properties(this, &continuation); |
| + if_dict_properties.Then(); |
| + { |
| + // Key is string, properties are dictionary mode |
| + BuildGlobalInstanceTypeCheck(receiver); |
| + |
| + HValue* properties = Add<HLoadNamedField>( |
| + receiver, static_cast<HValue*>(NULL), |
| + HObjectAccess::ForPropertiesPointer()); |
| + |
| + HValue* hash = |
| + Add<HLoadNamedField>(key, static_cast<HValue*>(NULL), |
| + HObjectAccess::ForNameHashField()); |
| + |
| + HValue* value = BuildUncheckedDictionaryElementLoad(receiver, |
| + properties, |
| + key, |
| + hash); |
| + Push(value); |
| + } |
| + if_dict_properties.Else(); |
| + { |
| + // Key is string, properties are fast mode |
| + HValue* hash = BuildKeyedLookupCacheHash(receiver, key); |
| + |
| + ExternalReference cache_keys_ref = |
| + ExternalReference::keyed_lookup_cache_keys(isolate()); |
| + HValue* cache_keys = Add<HConstant>(cache_keys_ref); |
| + |
| + HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL), |
| + HObjectAccess::ForMap()); |
| + HValue* base_index = AddUncasted<HMul>(hash, Add<HConstant>(2)); |
| + base_index->ClearFlag(HValue::kCanOverflow); |
| + |
| + IfBuilder lookup_if(this); |
| + for (int probe = 0; probe < KeyedLookupCache::kEntriesPerBucket; |
| + ++probe) { |
| + HValue* map_index = AddUncasted<HAdd>(base_index, |
| + Add<HConstant>(probe * 2)); |
|
Toon Verwaest
2014/06/10 11:33:43
* KeyedLookupCache::kEntryLength + KeyedLookupCach
danno
2014/06/11 08:08:00
Done.
|
| + map_index->ClearFlag(HValue::kCanOverflow); |
| + HValue* key_index = AddUncasted<HAdd>(base_index, |
| + Add<HConstant>(probe * 2 + 1)); |
|
Toon Verwaest
2014/06/10 11:33:43
+ KeyedLookupCache::kKeyIndex
danno
2014/06/11 08:08:00
Done.
|
| + key_index->ClearFlag(HValue::kCanOverflow); |
| + HValue* map_to_check = Add<HLoadKeyed>(cache_keys, |
| + map_index, |
| + static_cast<HValue*>(NULL), |
| + FAST_ELEMENTS, |
| + NEVER_RETURN_HOLE, 0); |
| + lookup_if.If<HCompareObjectEqAndBranch>(map_to_check, map); |
| + lookup_if.And(); |
| + HValue* key_to_check = Add<HLoadKeyed>(cache_keys, |
| + key_index, |
| + static_cast<HValue*>(NULL), |
| + FAST_ELEMENTS, |
| + NEVER_RETURN_HOLE, 0); |
| + lookup_if.If<HCompareObjectEqAndBranch>(key_to_check, key); |
| + lookup_if.Then(); |
| + { |
| + ExternalReference cache_field_offsets_ref = |
| + ExternalReference::keyed_lookup_cache_field_offsets(isolate()); |
| + HValue* cache_field_offsets = Add<HConstant>(cache_field_offsets_ref); |
| + HValue* index = AddUncasted<HAdd>(hash, |
| + Add<HConstant>(probe)); |
| + index->ClearFlag(HValue::kCanOverflow); |
| + HValue* property_index = Add<HLoadKeyed>(cache_field_offsets, |
| + index, |
| + static_cast<HValue*>(NULL), |
| + EXTERNAL_INT32_ELEMENTS, |
| + NEVER_RETURN_HOLE, 0); |
| + Push(property_index); |
| + } |
| + lookup_if.Else(); |
| + } |
| + Add<HDeoptimize>("KeyedLoad fall-back", Deoptimizer::EAGER); |
| + Push(graph()->GetConstant0()); |
| + lookup_if.End(); |
| + Push(Add<HLoadFieldByIndex>(receiver, Pop())); |
| + } |
| + if_dict_properties.End(); |
| + } |
| + index_name_split.End(); |
| + |
| + return Pop(); |
| +} |
| + |
| + |
| +Handle<Code> KeyedLoadGenericElementStub::GenerateCode() { |
| + return DoGenerateCode(this); |
| +} |
| + |
| + |
| } } // namespace v8::internal |