| 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
|
|
|