Index: src/code-stubs-hydrogen.cc |
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc |
index 88e71faca9ee9dca4db2991d81117fbb8568a147..1755405684bd19c63e250e0708e6cf184077f1cf 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,304 @@ 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); |
+ BuildJSObjectCheck(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); |
+ BuildJSObjectCheck(receiver, bit_field_mask); |
+ |
+ HIfContinuation continuation; |
+ BuildTestForDictionaryProperties(receiver, &continuation); |
+ IfBuilder if_dict_properties(this, &continuation); |
+ if_dict_properties.Then(); |
+ { |
+ // Key is string, properties are dictionary mode |
+ BuildNonGlobalObjectCheck(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) { |
+ int probe_base = probe * KeyedLookupCache::kEntryLength; |
+ HValue* map_index = AddUncasted<HAdd>(base_index, |
+ Add<HConstant>(probe_base + KeyedLookupCache::kMapIndex)); |
+ map_index->ClearFlag(HValue::kCanOverflow); |
+ HValue* key_index = AddUncasted<HAdd>(base_index, |
+ Add<HConstant>(probe_base + KeyedLookupCache::kKeyIndex)); |
+ 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 |