From 35f149e1d884935941b852aa1f9db997a7107457 Mon Sep 17 00:00:00 2001 From: Sathya Gunasekaran Date: Wed, 9 Aug 2017 22:04:09 +0000 Subject: [PATCH] Revert "[runtime] Store hash code in length field" This reverts commit decf5750c6421adf93b02135defa2b7c6c6fa755. Reason for revert: broken layout tests Original change's description: > [runtime] Store hash code in length field > > Store the hash code in 21 bits of the length field. > > Change the GetIdentityHash API to be unhandlified, since there's no > property lookup anymore. > > Update js/ and test/ to match new API and expections. > > Bug: > Change-Id: I8dc75de4021f59e79b45f3f38ec997c3b3687b24 > Reviewed-on: https://chromium-review.googlesource.com/589688 > Commit-Queue: Sathya Gunasekaran > Reviewed-by: Michael Starzinger > Reviewed-by: Ulan Degenbaev > Reviewed-by: Jakob Kummerow > Cr-Commit-Position: refs/heads/master@{#47259} TBR=ulan@chromium.org,jkummerow@chromium.org,mstarzinger@chromium.org,cbruni@chromium.org,gsathya@chromium.org Change-Id: I32db9c20a51b2401464924cafea502628a0d0b92 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/609322 Reviewed-by: Sathya Gunasekaran Commit-Queue: Sathya Gunasekaran Cr-Commit-Position: refs/heads/master@{#47260} --- src/builtins/builtins-constructor-gen.cc | 4 +- src/builtins/builtins-forin-gen.cc | 2 +- src/builtins/builtins-internal-gen.cc | 2 +- src/builtins/builtins-proxy-gen.cc | 2 +- src/code-stub-assembler.cc | 34 ++--- src/code-stub-assembler.h | 5 +- src/compiler/access-builder.cc | 28 ++-- src/compiler/access-builder.h | 3 +- src/compiler/js-builtin-reducer.cc | 30 ++-- src/compiler/js-create-lowering.cc | 28 ++-- .../js-native-context-specialization.cc | 16 +-- src/compiler/property-access-builder.cc | 2 +- src/compiler/type-cache.h | 5 + src/heap-symbols.h | 1 + src/heap/heap.h | 2 +- src/ic/accessor-assembler.cc | 37 ++--- src/ic/keyed-store-generic.cc | 4 +- src/js/weak-collection.js | 12 +- src/objects-inl.h | 49 +++---- src/objects.cc | 111 +++------------ src/objects.h | 129 ++++++++---------- src/objects/dictionary.h | 16 +-- src/runtime/runtime-collections.cc | 7 - src/runtime/runtime.h | 1 - test/cctest/test-api.cc | 2 +- test/cctest/test-dictionary.cc | 24 ++-- test/cctest/test-orderedhashtable.cc | 33 +++-- 27 files changed, 226 insertions(+), 363 deletions(-) diff --git a/src/builtins/builtins-constructor-gen.cc b/src/builtins/builtins-constructor-gen.cc index 3b373fca37..2aebb9cb01 100644 --- a/src/builtins/builtins-constructor-gen.cc +++ b/src/builtins/builtins-constructor-gen.cc @@ -623,14 +623,14 @@ Node* ConstructorBuiltinsAssembler::EmitFastCloneShallowObject( { Comment("Copy dictionary properties"); var_properties.Bind( - CopyNameDictionary(LoadSlowProperties(boilerplate), call_runtime)); + CopyNameDictionary(LoadProperties(boilerplate), call_runtime)); // Slow objects have no in-object properties. Goto(&done); } BIND(&if_fast); { // TODO(cbruni): support copying out-of-object properties. - Node* boilerplate_properties = LoadFastProperties(boilerplate); + Node* boilerplate_properties = LoadProperties(boilerplate); GotoIfNot(IsEmptyFixedArray(boilerplate_properties), call_runtime); var_properties.Bind(EmptyFixedArrayConstant()); Goto(&done); diff --git a/src/builtins/builtins-forin-gen.cc b/src/builtins/builtins-forin-gen.cc index 221473b294..8ee9907b86 100644 --- a/src/builtins/builtins-forin-gen.cc +++ b/src/builtins/builtins-forin-gen.cc @@ -148,7 +148,7 @@ void ForInBuiltinsAssembler::CheckEnumCache(Node* receiver, Label* use_cache, { // Avoid runtime-call for empty dictionary receivers. GotoIfNot(IsDictionaryMap(map), use_runtime); - Node* properties = LoadSlowProperties(receiver); + Node* properties = LoadProperties(receiver); Node* length = LoadFixedArrayElement( properties, NameDictionary::kNumberOfElementsIndex); GotoIfNot(WordEqual(length, SmiConstant(0)), use_runtime); diff --git a/src/builtins/builtins-internal-gen.cc b/src/builtins/builtins-internal-gen.cc index 7d126c4a31..60424e50fa 100644 --- a/src/builtins/builtins-internal-gen.cc +++ b/src/builtins/builtins-internal-gen.cc @@ -460,7 +460,7 @@ TF_BUILTIN(DeleteProperty, DeletePropertyBaseAssembler) { BIND(&dictionary); { - Node* properties = LoadSlowProperties(receiver); + Node* properties = LoadProperties(receiver); DeleteDictionaryProperty(receiver, properties, unique, context, &dont_delete, &if_notfound); } diff --git a/src/builtins/builtins-proxy-gen.cc b/src/builtins/builtins-proxy-gen.cc index 89bc4ccc1f..aa62e4d17b 100644 --- a/src/builtins/builtins-proxy-gen.cc +++ b/src/builtins/builtins-proxy-gen.cc @@ -78,7 +78,7 @@ class ProxiesCodeStubAssembler : public CodeStubAssembler { Node* proxy = Allocate(JSProxy::kSize); StoreMapNoWriteBarrier(proxy, map.value()); StoreObjectFieldRoot(proxy, JSProxy::kPropertiesOrHashOffset, - Heap::kEmptyPropertyDictionaryRootIndex); + Heap::kEmptyPropertiesDictionaryRootIndex); StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kTargetOffset, target); StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHandlerOffset, handler); StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHashOffset, diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index 4216a2b681..6653fa3a59 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -1152,18 +1152,9 @@ Node* CodeStubAssembler::TaggedDoesntHaveInstanceType(Node* any_tagged, MachineRepresentation::kBit); } -TNode CodeStubAssembler::LoadFastProperties( +TNode CodeStubAssembler::LoadProperties( SloppyTNode object) { - Node* properties = LoadObjectField(object, JSObject::kPropertiesOrHashOffset); - return SelectTaggedConstant( - TaggedIsSmi(properties), EmptyFixedArrayConstant(), properties); -} - -TNode CodeStubAssembler::LoadSlowProperties( - SloppyTNode object) { - Node* properties = LoadObjectField(object, JSObject::kPropertiesOrHashOffset); - return SelectTaggedConstant( - TaggedIsSmi(properties), EmptyPropertyDictionaryConstant(), properties); + return CAST(LoadObjectField(object, JSObject::kPropertiesOrHashOffset)); } TNode CodeStubAssembler::LoadElements( @@ -2257,9 +2248,6 @@ Node* CodeStubAssembler::AllocateNameDictionaryWithCapacity(Node* capacity) { StoreFixedArrayElement(result, NameDictionary::kNextEnumerationIndexIndex, SmiConstant(PropertyDetails::kInitialIndex), SKIP_WRITE_BARRIER); - StoreFixedArrayElement(result, NameDictionary::kObjectHashIndex, - SmiConstant(PropertyArray::kNoHashSentinel), - SKIP_WRITE_BARRIER); // Initialize NameDictionary elements. Node* result_word = BitcastTaggedToWord(result); @@ -2500,6 +2488,18 @@ void CodeStubAssembler::InitializePropertyArrayLength(Node* property_array, MachineRepresentation::kTaggedSigned); } +Node* CodeStubAssembler::LoadPropertyArrayLength(Node* property_array) { + // TODO(gsathya): Remove the IsEmptyFixedArray check once we have + // proper handling for the Smi case. + CSA_SLOW_ASSERT(this, Word32Or(IsEmptyFixedArray(property_array), + IsPropertyArray(property_array))); + Node* const value = + LoadObjectField(property_array, PropertyArray::kLengthOffset, + MachineType::TaggedSigned()); + Node* const length = SmiAnd(value, SmiConstant(PropertyArray::kLengthMask)); + return length; +} + Node* CodeStubAssembler::AllocatePropertyArray(Node* capacity_node, ParameterMode mode, AllocationFlags flags) { @@ -5733,7 +5733,7 @@ void CodeStubAssembler::TryLookupProperty( } BIND(&if_isslowmap); { - Node* dictionary = LoadSlowProperties(object); + Node* dictionary = LoadProperties(object); var_meta_storage->Bind(dictionary); NameDictionaryLookup(dictionary, unique_name, if_found_dict, @@ -5750,7 +5750,7 @@ void CodeStubAssembler::TryLookupProperty( int mask = 1 << Map::kHasNamedInterceptor | 1 << Map::kIsAccessCheckNeeded; GotoIf(IsSetWord32(bit_field, mask), if_bailout); - Node* dictionary = LoadSlowProperties(object); + Node* dictionary = LoadProperties(object); var_meta_storage->Bind(dictionary); NameDictionaryLookup( @@ -5857,7 +5857,7 @@ void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map, BIND(&if_backing_store); { Comment("if_backing_store"); - Node* properties = LoadFastProperties(object); + Node* properties = LoadProperties(object); field_index = IntPtrSub(field_index, inobject_properties); Node* value = LoadFixedArrayElement(properties, field_index); diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 45d51f0368..96d6c974cf 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -28,8 +28,6 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \ V(BooleanMap, boolean_map, BooleanMap) \ V(CodeMap, code_map, CodeMap) \ - V(EmptyPropertyDictionary, empty_property_dictionary, \ - EmptyPropertyDictionary) \ V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \ V(empty_string, empty_string, EmptyString) \ V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \ @@ -444,8 +442,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { Node* DoesntHaveInstanceType(Node* object, InstanceType type); Node* TaggedDoesntHaveInstanceType(Node* any_tagged, InstanceType type); // Load the properties backing store of a JSObject. - TNode LoadSlowProperties(SloppyTNode object); - TNode LoadFastProperties(SloppyTNode object); + TNode LoadProperties(SloppyTNode object); // Load the elements backing store of a JSObject. TNode LoadElements(SloppyTNode object); // Load the length of a JSArray instance. diff --git a/src/compiler/access-builder.cc b/src/compiler/access-builder.cc index 526a2a56de..cf25e15ac3 100644 --- a/src/compiler/access-builder.cc +++ b/src/compiler/access-builder.cc @@ -54,10 +54,10 @@ FieldAccess AccessBuilder::ForHeapNumberValue() { // static -FieldAccess AccessBuilder::ForJSObjectPropertiesOrHash() { +FieldAccess AccessBuilder::ForJSObjectProperties() { FieldAccess access = {kTaggedBase, JSObject::kPropertiesOrHashOffset, MaybeHandle(), MaybeHandle(), - Type::Any(), MachineType::AnyTagged(), + Type::Internal(), MachineType::TaggedPointer(), kPointerWriteBarrier}; return access; } @@ -477,11 +477,14 @@ FieldAccess AccessBuilder::ForFixedArrayLength() { } // static -// TODO(gsathya): Rename this to PropertyArrayLengthAndHash. FieldAccess AccessBuilder::ForPropertyArrayLength() { - FieldAccess access = {kTaggedBase, PropertyArray::kLengthOffset, - MaybeHandle(), MaybeHandle(), - Type::SignedSmall(), MachineType::TaggedSigned(), + // TODO(gsathya): Update the value range once we add the hash code. + FieldAccess access = {kTaggedBase, + PropertyArray::kLengthOffset, + MaybeHandle(), + MaybeHandle(), + TypeCache::Get().kPropertyArrayLengthType, + MachineType::TaggedSigned(), kNoWriteBarrier}; return access; } @@ -1112,19 +1115,6 @@ FieldAccess AccessBuilder::ForDictionaryNextEnumerationIndex() { return access; } -// static -FieldAccess AccessBuilder::ForDictionaryObjectHashIndex() { - FieldAccess access = { - kTaggedBase, - FixedArray::OffsetOfElementAt(NameDictionary::kObjectHashIndex), - MaybeHandle(), - MaybeHandle(), - Type::SignedSmall(), - MachineType::TaggedSigned(), - kNoWriteBarrier}; - return access; -} - } // namespace compiler } // namespace internal } // namespace v8 diff --git a/src/compiler/access-builder.h b/src/compiler/access-builder.h index 205dce7ad3..b78430cf4f 100644 --- a/src/compiler/access-builder.h +++ b/src/compiler/access-builder.h @@ -39,7 +39,7 @@ class V8_EXPORT_PRIVATE AccessBuilder final static FieldAccess ForHeapNumberValue(); // Provides access to JSObject::properties() field. - static FieldAccess ForJSObjectPropertiesOrHash(); + static FieldAccess ForJSObjectProperties(); // Provides access to JSObject::elements() field. static FieldAccess ForJSObjectElements(); @@ -303,7 +303,6 @@ class V8_EXPORT_PRIVATE AccessBuilder final // Provides access to Dictionary fields. static FieldAccess ForDictionaryMaxNumberKey(); static FieldAccess ForDictionaryNextEnumerationIndex(); - static FieldAccess ForDictionaryObjectHashIndex(); private: DISALLOW_IMPLICIT_CONSTRUCTORS(AccessBuilder); diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc index 5571fec968..e5dd18958b 100644 --- a/src/compiler/js-builtin-reducer.cc +++ b/src/compiler/js-builtin-reducer.cc @@ -303,8 +303,8 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Handle receiver_map, effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), value, jsgraph()->Constant(map), effect, control); effect = graph()->NewNode( - simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()), - value, jsgraph()->EmptyFixedArrayConstant(), effect, control); + simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, + jsgraph()->EmptyFixedArrayConstant(), effect, control); effect = graph()->NewNode( simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, jsgraph()->EmptyFixedArrayConstant(), effect, control); @@ -1250,8 +1250,8 @@ Reduction JSBuiltinReducer::ReduceCollectionIterator( simplified()->StoreField(AccessBuilder::ForMap()), value, jsgraph()->Constant(collection_iterator_map), effect, control); effect = graph()->NewNode( - simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()), - value, jsgraph()->EmptyFixedArrayConstant(), effect, control); + simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, + jsgraph()->EmptyFixedArrayConstant(), effect, control); effect = graph()->NewNode( simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, jsgraph()->EmptyFixedArrayConstant(), effect, control); @@ -1668,8 +1668,8 @@ Reduction JSBuiltinReducer::ReduceFunctionBind(Node* node) { effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), value, jsgraph()->Constant(map), effect, control); effect = graph()->NewNode( - simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()), - value, jsgraph()->EmptyFixedArrayConstant(), effect, control); + simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, + jsgraph()->EmptyFixedArrayConstant(), effect, control); effect = graph()->NewNode( simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, jsgraph()->EmptyFixedArrayConstant(), effect, control); @@ -2345,15 +2345,9 @@ Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) { AccessBuilder::ForDictionaryNextEnumerationIndex()), value, jsgraph()->SmiConstant(PropertyDetails::kInitialIndex), effect, control); - effect = graph()->NewNode( - simplified()->StoreField(AccessBuilder::ForDictionaryObjectHashIndex()), - value, jsgraph()->SmiConstant(PropertyArray::kNoHashSentinel), effect, - control); // Initialize the Properties fields. - STATIC_ASSERT(NameDictionary::kElementsStartIndex == - NameDictionary::kObjectHashIndex + 1); - for (int index = NameDictionary::kElementsStartIndex; index < length; - index++) { + for (int index = NameDictionary::kNextEnumerationIndexIndex + 1; + index < length; index++) { effect = graph()->NewNode( simplified()->StoreField( AccessBuilder::ForFixedArraySlot(index, kNoWriteBarrier)), @@ -2378,8 +2372,8 @@ Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) { graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), value, jsgraph()->HeapConstant(instance_map), effect, control); effect = graph()->NewNode( - simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()), - value, properties, effect, control); + simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, + properties, effect, control); effect = graph()->NewNode( simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, jsgraph()->EmptyFixedArrayConstant(), effect, control); @@ -2622,8 +2616,8 @@ Reduction JSBuiltinReducer::ReduceStringIterator(Node* node) { effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), value, map, effect, control); effect = graph()->NewNode( - simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()), - value, jsgraph()->EmptyFixedArrayConstant(), effect, control); + simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value, + jsgraph()->EmptyFixedArrayConstant(), effect, control); effect = graph()->NewNode( simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value, jsgraph()->EmptyFixedArrayConstant(), effect, control); diff --git a/src/compiler/js-create-lowering.cc b/src/compiler/js-create-lowering.cc index 9d2f214d5d..6f7c500940 100644 --- a/src/compiler/js-create-lowering.cc +++ b/src/compiler/js-create-lowering.cc @@ -276,7 +276,7 @@ Reduction JSCreateLowering::ReduceJSCreate(Node* node) { AllocationBuilder a(jsgraph(), effect, control); a.Allocate(instance_size); a.Store(AccessBuilder::ForMap(), initial_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), + a.Store(AccessBuilder::ForJSObjectProperties(), jsgraph()->EmptyFixedArrayConstant()); a.Store(AccessBuilder::ForJSObjectElements(), jsgraph()->EmptyFixedArrayConstant()); @@ -333,7 +333,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize); a.Allocate(JSSloppyArgumentsObject::kSize); a.Store(AccessBuilder::ForMap(), arguments_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForArgumentsLength(), arguments_length); a.Store(AccessBuilder::ForArgumentsCallee(), callee); @@ -379,7 +379,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); a.Allocate(JSStrictArgumentsObject::kSize); a.Store(AccessBuilder::ForMap(), arguments_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForArgumentsLength(), arguments_length); RelaxControls(node); @@ -424,7 +424,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); a.Allocate(JSArray::kSize); a.Store(AccessBuilder::ForMap(), jsarray_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), rest_length); @@ -479,7 +479,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { STATIC_ASSERT(JSSloppyArgumentsObject::kSize == 5 * kPointerSize); a.Allocate(JSSloppyArgumentsObject::kSize); a.Store(AccessBuilder::ForMap(), arguments_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); a.Store(AccessBuilder::ForArgumentsCallee(), callee); @@ -508,7 +508,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { STATIC_ASSERT(JSStrictArgumentsObject::kSize == 4 * kPointerSize); a.Allocate(JSStrictArgumentsObject::kSize); a.Store(AccessBuilder::ForMap(), arguments_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForArgumentsLength(), jsgraph()->Constant(length)); RelaxControls(node); @@ -543,7 +543,7 @@ Reduction JSCreateLowering::ReduceJSCreateArguments(Node* node) { STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); a.Allocate(JSArray::kSize); a.Store(AccessBuilder::ForMap(), jsarray_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), jsgraph()->Constant(length)); @@ -593,7 +593,7 @@ Reduction JSCreateLowering::ReduceJSCreateGeneratorObject(Node* node) { Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant(); Node* undefined = jsgraph()->UndefinedConstant(); a.Store(AccessBuilder::ForMap(), initial_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), empty_fixed_array); + a.Store(AccessBuilder::ForJSObjectProperties(), empty_fixed_array); a.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array); a.Store(AccessBuilder::ForJSGeneratorObjectContext(), context); a.Store(AccessBuilder::ForJSGeneratorObjectFunction(), closure); @@ -660,7 +660,7 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, Node* length, AllocationBuilder a(jsgraph(), effect, control); a.Allocate(JSArray::kSize, pretenure); a.Store(AccessBuilder::ForMap(), js_array_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length); RelaxControls(node); @@ -719,7 +719,7 @@ Reduction JSCreateLowering::ReduceNewArray(Node* node, AllocationBuilder a(jsgraph(), effect, control); a.Allocate(JSArray::kSize, pretenure); a.Store(AccessBuilder::ForMap(), js_array_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForJSArrayLength(elements_kind), length); RelaxControls(node); @@ -851,7 +851,7 @@ Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) { AllocationBuilder a(jsgraph(), effect, graph()->start()); a.Allocate(JSIteratorResult::kSize); a.Store(AccessBuilder::ForMap(), iterator_result_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), + a.Store(AccessBuilder::ForJSObjectProperties(), jsgraph()->EmptyFixedArrayConstant()); a.Store(AccessBuilder::ForJSObjectElements(), jsgraph()->EmptyFixedArrayConstant()); @@ -884,7 +884,7 @@ Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) { AllocationBuilder a(jsgraph(), elements, graph()->start()); a.Allocate(JSArray::kSize); a.Store(AccessBuilder::ForMap(), array_map); - a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + a.Store(AccessBuilder::ForJSObjectProperties(), properties); a.Store(AccessBuilder::ForJSObjectElements(), elements); a.Store(AccessBuilder::ForJSArrayLength(PACKED_ELEMENTS), length); STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize); @@ -1349,7 +1349,7 @@ Node* JSCreateLowering::AllocateFastLiteral( builder.Allocate(boilerplate_map->instance_size(), pretenure, Type::For(boilerplate_map)); builder.Store(AccessBuilder::ForMap(), boilerplate_map); - builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), properties); + builder.Store(AccessBuilder::ForJSObjectProperties(), properties); builder.Store(AccessBuilder::ForJSObjectElements(), elements); if (boilerplate_map->IsJSArrayMap()) { Handle boilerplate_array = Handle::cast(boilerplate); @@ -1455,7 +1455,7 @@ Node* JSCreateLowering::AllocateLiteralRegExp(Node* effect, Node* control, AllocationBuilder builder(jsgraph(), effect, control); builder.Allocate(size, pretenure, Type::For(boilerplate_map)); builder.Store(AccessBuilder::ForMap(), boilerplate_map); - builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), + builder.Store(AccessBuilder::ForJSObjectProperties(), handle(boilerplate->raw_properties_or_hash(), isolate())); builder.Store(AccessBuilder::ForJSObjectElements(), handle(boilerplate->elements(), isolate())); diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc index eb6b3a13b5..f4f66268f1 100644 --- a/src/compiler/js-native-context-specialization.cc +++ b/src/compiler/js-native-context-specialization.cc @@ -1654,7 +1654,7 @@ JSNativeContextSpecialization::BuildPropertyStore( Node* storage = receiver; if (!field_index.is_inobject()) { storage = effect = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()), + simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), storage, effect, control); } FieldAccess field_access = { @@ -1800,7 +1800,7 @@ JSNativeContextSpecialization::BuildPropertyStore( storage, value, effect, control); // Atomically switch to the new properties below. - field_access = AccessBuilder::ForJSObjectPropertiesOrHash(); + field_access = AccessBuilder::ForJSObjectProperties(); value = storage; storage = receiver; } @@ -2242,17 +2242,8 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore( values.push_back(jsgraph()->UndefinedConstant()); } // Allocate and initialize the new properties. - Node* new_length_and_hash = effect = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForPropertyArrayLength()), - properties, effect, control); effect = graph()->NewNode( common()->BeginRegion(RegionObservability::kNotObservable), effect); - new_length_and_hash = - graph()->NewNode(simplified()->NumberBitwiseAnd(), new_length_and_hash, - jsgraph()->Constant(JSReceiver::kHashMask)); - new_length_and_hash = - graph()->NewNode(simplified()->NumberBitwiseOr(), new_length_and_hash, - jsgraph()->Constant(new_length)); Node* new_properties = effect = graph()->NewNode( simplified()->Allocate(Type::OtherInternal(), NOT_TENURED), jsgraph()->Constant(PropertyArray::SizeFor(new_length)), effect, control); @@ -2261,12 +2252,13 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore( jsgraph()->PropertyArrayMapConstant(), effect, control); effect = graph()->NewNode( simplified()->StoreField(AccessBuilder::ForPropertyArrayLength()), - new_properties, new_length_and_hash, effect, control); + new_properties, jsgraph()->Constant(new_length), effect, control); for (int i = 0; i < new_length; ++i) { effect = graph()->NewNode( simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), new_properties, values[i], effect, control); } + // TODO(gsathya): Update hash code here. return graph()->NewNode(common()->FinishRegion(), new_properties, effect); } diff --git a/src/compiler/property-access-builder.cc b/src/compiler/property-access-builder.cc index 12f3eddcda..4edc3ee300 100644 --- a/src/compiler/property-access-builder.cc +++ b/src/compiler/property-access-builder.cc @@ -224,7 +224,7 @@ Node* PropertyAccessBuilder::BuildLoadDataField( Node* storage = receiver; if (!field_index.is_inobject()) { storage = *effect = graph()->NewNode( - simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()), + simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), storage, *effect, *control); } FieldAccess field_access = { diff --git a/src/compiler/type-cache.h b/src/compiler/type-cache.h index 5ac9072174..2241fd4661 100644 --- a/src/compiler/type-cache.h +++ b/src/compiler/type-cache.h @@ -83,6 +83,11 @@ class TypeCache final { // [0, FixedArray::kMaxLength]. Type* const kFixedArrayLengthType = CreateRange(0.0, FixedArray::kMaxLength); + // The PropertyArray::length property always containts a smi in the range + // [0, PropertyArray::kMaxLength]. + Type* const kPropertyArrayLengthType = + CreateRange(0.0, PropertyArray::kMaxLength); + // The FixedDoubleArray::length property always containts a smi in the range // [0, FixedDoubleArray::kMaxLength]. Type* const kFixedDoubleArrayLengthType = diff --git a/src/heap-symbols.h b/src/heap-symbols.h index 1834dd9b9b..4577e002f4 100644 --- a/src/heap-symbols.h +++ b/src/heap-symbols.h @@ -221,6 +221,7 @@ V(error_script_symbol) \ V(error_start_pos_symbol) \ V(frozen_symbol) \ + V(hash_code_symbol) \ V(home_object_symbol) \ V(intl_initialized_marker_symbol) \ V(intl_pattern_symbol) \ diff --git a/src/heap/heap.h b/src/heap/heap.h index 77623ffca3..dd73e21319 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -194,7 +194,7 @@ using v8::MemoryPressureLevel; V(FixedArray, string_split_cache, StringSplitCache) \ V(FixedArray, regexp_multiple_cache, RegExpMultipleCache) \ /* Lists and dictionaries */ \ - V(NameDictionary, empty_property_dictionary, EmptyPropertyDictionary) \ + V(NameDictionary, empty_property_dictionary, EmptyPropertiesDictionary) \ V(NameDictionary, public_symbol_table, PublicSymbolTable) \ V(NameDictionary, api_symbol_table, ApiSymbolTable) \ V(NameDictionary, api_private_symbol_table, ApiPrivateSymbolTable) \ diff --git a/src/ic/accessor-assembler.cc b/src/ic/accessor-assembler.cc index 3f545777d3..82fd0bba2f 100644 --- a/src/ic/accessor-assembler.cc +++ b/src/ic/accessor-assembler.cc @@ -195,7 +195,7 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word, BIND(&out_of_object); { Label is_double(this); - Node* properties = LoadFastProperties(holder); + Node* properties = LoadProperties(holder); Node* value = LoadObjectField(properties, offset); GotoIf(IsSetWord(handler_word), &is_double); exit_point->Return(value); @@ -322,7 +322,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( BIND(&normal); { Comment("load_normal"); - Node* properties = LoadSlowProperties(holder); + Node* properties = LoadProperties(holder); VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label found(this, &var_name_index); NameDictionaryLookup(properties, p->name, &found, @@ -423,7 +423,7 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase( { CSA_ASSERT(this, Word32BinaryNot( HasInstanceType(p->receiver, JS_GLOBAL_OBJECT_TYPE))); - Node* properties = LoadSlowProperties(p->receiver); + Node* properties = LoadProperties(p->receiver); VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label found(this, &var_name_index); NameDictionaryLookup(properties, p->name, &found, @@ -593,7 +593,7 @@ void AccessorAssembler::HandleStoreICHandlerCase( WordEqual(handler_word, IntPtrConstant(StoreHandler::kStoreNormal)), &if_fast_smi); - Node* properties = LoadSlowProperties(holder); + Node* properties = LoadProperties(holder); VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label dictionary_found(this, &var_name_index); @@ -841,7 +841,7 @@ void AccessorAssembler::HandleStoreICProtoHandler( BIND(&if_store_normal); { - Node* properties = LoadSlowProperties(p->receiver); + Node* properties = LoadProperties(p->receiver); VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label found(this, &var_name_index), not_found(this); @@ -1050,14 +1050,8 @@ void AccessorAssembler::ExtendPropertiesBackingStore(Node* object, ParameterMode mode = OptimalParameterMode(); - // TODO(gsathya): Clean up the type conversions by creating smarter - // helpers that do the correct op based on the mode. - Node* properties = LoadFastProperties(object); - Node* length_and_hash_int32 = - LoadAndUntagToWord32ObjectField(properties, PropertyArray::kLengthOffset); - Node* length_intptr = ChangeInt32ToIntPtr(Word32And( - length_and_hash_int32, Int32Constant(PropertyArray::kLengthMask))); - Node* length = WordToParameter(length_intptr, mode); + Node* properties = LoadProperties(object); + Node* length = TaggedToParameter(LoadPropertyArrayLength(properties), mode); // Previous property deletion could have left behind unused backing store // capacity even for a map that think it doesn't have any unused fields. @@ -1091,16 +1085,7 @@ void AccessorAssembler::ExtendPropertiesBackingStore(Node* object, CopyPropertyArrayValues(properties, new_properties, length, SKIP_WRITE_BARRIER, mode); - // TODO(gsathya): Clean up the type conversions by creating smarter - // helpers that do the correct op based on the mode. - Node* masked_hash_int32 = - Word32And(length_and_hash_int32, Int32Constant(JSReceiver::kHashMask)); - Node* new_capacity_int32 = - TruncateWordToWord32(ParameterToWord(new_capacity, mode)); - Node* new_length_and_hash_int32 = - Word32Or(masked_hash_int32, new_capacity_int32); - StoreObjectField(new_properties, PropertyArray::kLengthOffset, - SmiFromWord32(new_length_and_hash_int32)); + // TODO(gsathya): Update hash code here. StoreObjectField(object, JSObject::kPropertiesOrHashOffset, new_properties); Comment("] Extend storage"); Goto(&done); @@ -1116,7 +1101,7 @@ void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object, bool store_value_as_double = representation.IsDouble(); Node* property_storage = object; if (!is_inobject) { - property_storage = LoadFastProperties(object); + property_storage = LoadProperties(object); } Node* offset = DecodeWord(handler_word); @@ -1417,7 +1402,7 @@ void AccessorAssembler::CheckPrototype(Node* prototype_cell, Node* name, void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss) { CSA_ASSERT(this, IsDictionaryMap(LoadMap(object))); - Node* properties = LoadSlowProperties(object); + Node* properties = LoadProperties(object); // Ensure the property does not exist in a dictionary-mode object. VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label done(this); @@ -1550,7 +1535,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map, VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label dictionary_found(this, &var_name_index); - Node* properties = LoadSlowProperties(receiver); + Node* properties = LoadProperties(receiver); NameDictionaryLookup(properties, p->name, &dictionary_found, &var_name_index, &lookup_prototype_chain); diff --git a/src/ic/keyed-store-generic.cc b/src/ic/keyed-store-generic.cc index d2a82f7077..a14a846508 100644 --- a/src/ic/keyed-store-generic.cc +++ b/src/ic/keyed-store-generic.cc @@ -784,7 +784,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( BIND(&data_property); { CheckForAssociatedProtector(p->name, slow); - Node* properties = LoadFastProperties(receiver); + Node* properties = LoadProperties(receiver); OverwriteExistingFastProperty(receiver, receiver_map, properties, descriptors, name_index, details, p->value, slow); @@ -854,7 +854,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore( VARIABLE(var_name_index, MachineType::PointerRepresentation()); Label dictionary_found(this, &var_name_index), not_found(this); - Node* properties = LoadSlowProperties(receiver); + Node* properties = LoadProperties(receiver); NameDictionaryLookup(properties, p->name, &dictionary_found, &var_name_index, ¬_found); BIND(&dictionary_found); diff --git a/src/js/weak-collection.js b/src/js/weak-collection.js index b895bcde61..4a6250d0ac 100644 --- a/src/js/weak-collection.js +++ b/src/js/weak-collection.js @@ -11,6 +11,7 @@ // ------------------------------------------------------------------- // Imports +var hashCodeSymbol = utils.ImportNow("hash_code_symbol"); var GlobalWeakMap = global.WeakMap; var GlobalWeakSet = global.WeakSet; var MathRandom = global.Math.random; @@ -19,7 +20,8 @@ var MathRandom = global.Math.random; function GetExistingHash(key) { if (IS_RECEIVER(key) && !IS_PROXY(key) && !IS_GLOBAL(key)) { - return %GetExistingHash(key); + var hash = GET_PRIVATE(key, hashCodeSymbol); + return hash; } return %GenericHash(key); } @@ -27,7 +29,13 @@ function GetExistingHash(key) { function GetHash(key) { - return %GenericHash(key); + var hash = GetExistingHash(key); + if (IS_UNDEFINED(hash)) { + hash = (MathRandom() * 0x40000000) | 0; + if (hash === 0) hash = 1; + SET_PRIVATE(key, hashCodeSymbol, hash); + } + return hash; } %SetForceInlineFlag(GetHash); diff --git a/src/objects-inl.h b/src/objects-inl.h index 3291e3ef37..010ac2e06e 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2681,9 +2681,9 @@ SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset) SYNCHRONIZED_SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset) int PropertyArray::length() const { - Object* value_obj = READ_FIELD(this, kLengthOffset); - int value = Smi::ToInt(value_obj); - return value & kLengthMask; + Object* value = READ_FIELD(this, kLengthOffset); + int len = Smi::ToInt(value); + return len & kLengthMask; } void PropertyArray::initialize_length(int len) { @@ -2693,23 +2693,9 @@ void PropertyArray::initialize_length(int len) { } int PropertyArray::synchronized_length() const { - Object* value_obj = ACQUIRE_READ_FIELD(this, kLengthOffset); - int value = Smi::ToInt(value_obj); - return value & kLengthMask; -} - -int PropertyArray::Hash() const { - Object* value_obj = READ_FIELD(this, kLengthOffset); - int value = Smi::ToInt(value_obj); - int hash = value & kHashMask; - return hash; -} - -void PropertyArray::SetHash(int masked_hash) { - Object* value_obj = READ_FIELD(this, kLengthOffset); - int value = Smi::ToInt(value_obj); - value |= masked_hash; - WRITE_FIELD(this, kLengthOffset, Smi::FromInt(value)); + Object* value = ACQUIRE_READ_FIELD(this, kLengthOffset); + int len = Smi::ToInt(value); + return len & kLengthMask; } SMI_ACCESSORS(FreeSpace, size, kSizeOffset) @@ -5473,7 +5459,7 @@ bool JSObject::HasIndexedInterceptor() { void JSGlobalObject::set_global_dictionary(GlobalDictionary* dictionary) { DCHECK(IsJSGlobalObject()); - set_raw_properties_or_hash(dictionary); + return SetProperties(dictionary); } GlobalDictionary* JSGlobalObject::global_dictionary() { @@ -5602,13 +5588,7 @@ bool JSReceiver::HasFastProperties() const { NameDictionary* JSReceiver::property_dictionary() const { DCHECK(!IsJSGlobalObject()); DCHECK(!HasFastProperties()); - - Object* prop = raw_properties_or_hash(); - if (prop->IsSmi()) { - return GetHeap()->empty_property_dictionary(); - } - - return NameDictionary::cast(prop); + return NameDictionary::cast(raw_properties_or_hash()); } // TODO(gsathya): Pass isolate directly to this function and access @@ -5624,6 +5604,11 @@ PropertyArray* JSReceiver::property_array() const { return PropertyArray::cast(prop); } +void JSReceiver::SetProperties(HeapObject* properties) { + // TODO(gsathya): Update the hash code here. + set_raw_properties_or_hash(properties); +} + Maybe JSReceiver::HasProperty(Handle object, Handle name) { LookupIterator it = LookupIterator::PropertyOrElement(object->GetIsolate(), @@ -5716,10 +5701,12 @@ Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate, isolate, Handle::cast(object)); } -Object* JSReceiver::GetIdentityHash(Isolate* isolate, JSReceiver* receiver) { +Object* JSReceiver::GetIdentityHash(Isolate* isolate, + Handle receiver) { return receiver->IsJSProxy() - ? JSProxy::GetIdentityHash(JSProxy::cast(receiver)) - : JSObject::GetIdentityHash(isolate, JSObject::cast(receiver)); + ? JSProxy::GetIdentityHash(Handle::cast(receiver)) + : JSObject::GetIdentityHash(isolate, + Handle::cast(receiver)); } diff --git a/src/objects.cc b/src/objects.cc index 53b29a72a8..964867e80b 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2322,7 +2322,7 @@ Object* Object::GetHash() { DCHECK(IsJSReceiver()); JSReceiver* receiver = JSReceiver::cast(this); Isolate* isolate = receiver->GetIsolate(); - return JSReceiver::GetIdentityHash(isolate, receiver); + return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate)); } Smi* Object::GetOrCreateHash(Isolate* isolate, Handle object) { @@ -6257,74 +6257,6 @@ Handle JSObject::NormalizeElements( return dictionary; } -namespace { - -Object* SetHashAndUpdateProperties(HeapObject* properties, int masked_hash) { - DCHECK_NE(PropertyArray::kNoHashSentinel, masked_hash); - DCHECK_EQ(masked_hash & JSReceiver::kHashMask, masked_hash); - - if (properties == properties->GetHeap()->empty_fixed_array() || - properties == properties->GetHeap()->empty_property_dictionary()) { - return Smi::FromInt(masked_hash); - } - - if (properties->IsPropertyArray()) { - PropertyArray::cast(properties)->SetHash(masked_hash); - return properties; - } - - DCHECK(properties->IsDictionary()); - NameDictionary::cast(properties)->SetHash(masked_hash); - return properties; -} - -int GetIdentityHashHelper(Isolate* isolate, JSReceiver* object) { - Object* properties = object->raw_properties_or_hash(); - if (properties->IsSmi()) { - return Smi::ToInt(properties); - } - - if (properties->IsPropertyArray()) { - return PropertyArray::cast(properties)->Hash(); - } - - if (properties->IsDictionary()) { - return NameDictionary::cast(properties)->Hash(); - } - -#ifdef DEBUG - FixedArray* empty_fixed_array = isolate->heap()->empty_fixed_array(); - FixedArray* empty_property_dictionary = - isolate->heap()->empty_property_dictionary(); - DCHECK(properties == empty_fixed_array || - properties == empty_property_dictionary); -#endif - - return PropertyArray::kNoHashSentinel; -} -} // namespace - -void JSReceiver::SetIdentityHash(int masked_hash) { - DCHECK_NE(PropertyArray::kNoHashSentinel, masked_hash); - DCHECK_EQ(masked_hash & JSReceiver::kHashMask, masked_hash); - - HeapObject* existing_properties = HeapObject::cast(raw_properties_or_hash()); - Object* new_properties = - SetHashAndUpdateProperties(existing_properties, masked_hash); - set_raw_properties_or_hash(new_properties); -} - -void JSReceiver::SetProperties(HeapObject* properties) { - Isolate* isolate = properties->GetIsolate(); - int hash = GetIdentityHashHelper(isolate, this); - Object* new_properties = properties; - - if (hash != PropertyArray::kNoHashSentinel) { - new_properties = SetHashAndUpdateProperties(properties, hash); - } - - set_raw_properties_or_hash(new_properties); -} template static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate, @@ -6338,17 +6270,12 @@ static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate, } // static -Object* JSObject::GetIdentityHash(Isolate* isolate, JSObject* object) { +Object* JSObject::GetIdentityHash(Isolate* isolate, Handle object) { if (object->IsJSGlobalProxy()) { - return JSGlobalProxy::cast(object)->hash(); + return JSGlobalProxy::cast(*object)->hash(); } - - int hash = GetIdentityHashHelper(isolate, object); - if (hash == PropertyArray::kNoHashSentinel) { - return isolate->heap()->undefined_value(); - } - - return Smi::FromInt(hash); + Handle hash_code_symbol = isolate->factory()->hash_code_symbol(); + return *JSReceiver::GetDataProperty(object, hash_code_symbol); } // static @@ -6359,23 +6286,25 @@ Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate, Handle::cast(object)); } - Object* hash_obj = JSObject::GetIdentityHash(isolate, *object); - if (hash_obj != isolate->heap()->undefined_value()) { - return Smi::cast(hash_obj); + Handle hash_code_symbol = isolate->factory()->hash_code_symbol(); + LookupIterator it(object, hash_code_symbol, object, LookupIterator::OWN); + if (it.IsFound()) { + DCHECK_EQ(LookupIterator::DATA, it.state()); + Object* maybe_hash = *it.GetDataValue(); + if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash); } - int hash; - do { - hash = isolate->GenerateIdentityHash(Smi::kMaxValue); - } while (hash == PropertyArray::kNoHashSentinel); - - int masked_hash = hash & JSReceiver::kHashMask; - object->SetIdentityHash(masked_hash); - return Smi::FromInt(masked_hash); + Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue)); + CHECK(AddDataProperty(&it, handle(hash, isolate), NONE, THROW_ON_ERROR, + CERTAINLY_NOT_STORE_FROM_KEYED) + .IsJust()); + return hash; } // static -Object* JSProxy::GetIdentityHash(JSProxy* proxy) { return proxy->hash(); } +Object* JSProxy::GetIdentityHash(Handle proxy) { + return proxy->hash(); +} Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle proxy) { return GetOrCreateIdentityHashHelper(isolate, proxy); @@ -17405,6 +17334,7 @@ Handle ObjectHashSet::Add(Handle set, Handle key) { Isolate* isolate = set->GetIsolate(); int32_t hash = Object::GetOrCreateHash(isolate, key)->value(); + if (!set->Has(isolate, key, hash)) { set = EnsureCapacity(set, 1); int entry = set->FindInsertionEntry(hash); @@ -17723,7 +17653,6 @@ Handle BaseNameDictionary::New( DCHECK_LE(0, at_least_space_for); Handle dict = Dictionary::New( isolate, at_least_space_for, pretenure, capacity_option); - dict->SetHash(PropertyArray::kNoHashSentinel); dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex); return dict; } diff --git a/src/objects.h b/src/objects.h index 1440269aad..d8d39ccdf3 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1945,62 +1945,6 @@ enum class KeyCollectionMode { enum class AllocationSiteUpdateMode { kUpdate, kCheckOnly }; -class PropertyArray : public HeapObject { - public: - // [length]: length of the array. - inline int length() const; - - // Get the length using acquire loads. - inline int synchronized_length() const; - - // This is only used on a newly allocated PropertyArray which - // doesn't have an existing hash. - inline void initialize_length(int length); - - inline void SetHash(int hash); - inline int Hash() const; - - inline Object* get(int index) const; - - inline void set(int index, Object* value); - // Setter with explicit barrier mode. - inline void set(int index, Object* value, WriteBarrierMode mode); - - // Gives access to raw memory which stores the array's data. - inline Object** data_start(); - - // Garbage collection support. - static constexpr int SizeFor(int length) { - return kHeaderSize + length * kPointerSize; - } - - DECL_CAST(PropertyArray) - DECL_PRINTER(PropertyArray) - DECL_VERIFIER(PropertyArray) - - // Layout description. - // TODO(gsathya): Rename kLengthOffset to kLengthAndHashOffset. - static const int kLengthOffset = HeapObject::kHeaderSize; - static const int kHeaderSize = kLengthOffset + kPointerSize; - - // Garbage collection support. - typedef FlexibleBodyDescriptor BodyDescriptor; - // No weak fields. - typedef BodyDescriptor BodyDescriptorWeak; - - static const int kLengthMask = 0x3ff; - static const int kHashMask = 0x7ffffc00; - STATIC_ASSERT(kLengthMask + kHashMask == 0x7fffffff); - - static const int kMaxLength = kLengthMask; - STATIC_ASSERT(kMaxLength > kMaxNumberOfDescriptors); - - static const int kNoHashSentinel = 0; - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyArray); -}; - // JSReceiver includes types on which properties can be defined, i.e., // JSObject and JSProxy. class JSReceiver: public HeapObject { @@ -2017,13 +1961,12 @@ class JSReceiver: public HeapObject { // Gets slow properties for non-global objects. inline NameDictionary* property_dictionary() const; - void SetProperties(HeapObject* properties); + inline void SetProperties(HeapObject* properties); - // There are five possible values for the properties offset. - // 1) EmptyFixedArray/EmptyPropertyDictionary - This is the standard - // placeholder. + // There are four possible value for the properties offset. + // 1) EmptyFixedArray -- This is the standard placeholder. // - // 2) Smi - This is the hash code of the object. + // 2) TODO(gsathya): Smi -- This is the hash code of the object. // // 3) PropertyArray - This is similar to a FixedArray but stores // the hash code of the object in its length field. This is a fast @@ -2031,9 +1974,6 @@ class JSReceiver: public HeapObject { // // 4) NameDictionary - This is the dictionary-mode backing store. // - // 4) GlobalDictionary - This is the backing store for the - // GlobalObject. - // // This is used only in the deoptimizer and heap. Please use the // above typed getters and setters to access the properties. DECL_ACCESSORS(raw_properties_or_hash, Object) @@ -2200,17 +2140,14 @@ class JSReceiver: public HeapObject { // Retrieves a permanent object identity hash code. The undefined value might // be returned in case no hash was created yet. - static inline Object* GetIdentityHash(Isolate* isolate, JSReceiver* object); + static inline Object* GetIdentityHash(Isolate* isolate, + Handle object); // Retrieves a permanent object identity hash code. May create and store a // hash code if needed and none exists. inline static Smi* GetOrCreateIdentityHash(Isolate* isolate, Handle object); - // Stores the hash code. The hash passed in must be masked with - // JSReceiver::kHashMask. - void SetIdentityHash(int masked_hash); - // ES6 [[OwnPropertyKeys]] (modulo return type) MUST_USE_RESULT static inline MaybeHandle OwnPropertyKeys( Handle object); @@ -2221,8 +2158,6 @@ class JSReceiver: public HeapObject { MUST_USE_RESULT static MaybeHandle GetOwnEntries( Handle object, PropertyFilter filter); - static const int kHashMask = PropertyArray::kHashMask; - // Layout description. static const int kPropertiesOrHashOffset = HeapObject::kHeaderSize; static const int kHeaderSize = HeapObject::kHeaderSize + kPointerSize; @@ -2728,7 +2663,7 @@ class JSObject: public JSReceiver { ElementsKind kind, Object* object); - static Object* GetIdentityHash(Isolate* isolate, JSObject* object); + static Object* GetIdentityHash(Isolate* isolate, Handle object); static Smi* GetOrCreateIdentityHash(Isolate* isolate, Handle object); @@ -3106,6 +3041,54 @@ class ArrayList : public FixedArray { DISALLOW_IMPLICIT_CONSTRUCTORS(ArrayList); }; +class PropertyArray : public HeapObject { + public: + // [length]: length of the array. + inline int length() const; + + // Get the length using acquire loads. + inline int synchronized_length() const; + + // This is only used on a newly allocated PropertyArray which + // doesn't have an existing hash. + inline void initialize_length(int length); + + inline Object* get(int index) const; + + // Setter that doesn't need write barrier. + inline void set(int index, Object* value); + // Setter with explicit barrier mode. + inline void set(int index, Object* value, WriteBarrierMode mode); + + // Gives access to raw memory which stores the array's data. + inline Object** data_start(); + + // Garbage collection support. + static constexpr int SizeFor(int length) { + return kHeaderSize + length * kPointerSize; + } + + DECL_CAST(PropertyArray) + DECL_PRINTER(PropertyArray) + DECL_VERIFIER(PropertyArray) + + // Layout description. + static const int kLengthOffset = HeapObject::kHeaderSize; + static const int kHeaderSize = kLengthOffset + kPointerSize; + + // Garbage collection support. + typedef FlexibleBodyDescriptor BodyDescriptor; + // No weak fields. + typedef BodyDescriptor BodyDescriptorWeak; + + static const int kLengthMask = 1023; + static const int kMaxLength = kLengthMask; + STATIC_ASSERT(kMaxLength > kMaxNumberOfDescriptors); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyArray); +}; + enum SearchMode { ALL_ENTRIES, VALID_ENTRIES }; template @@ -6355,7 +6338,7 @@ class JSProxy: public JSReceiver { // No weak fields. typedef BodyDescriptor BodyDescriptorWeak; - static Object* GetIdentityHash(JSProxy* receiver); + static Object* GetIdentityHash(Handle receiver); static Smi* GetOrCreateIdentityHash(Isolate* isolate, Handle proxy); diff --git a/src/objects/dictionary.h b/src/objects/dictionary.h index a989c8fc8a..bb8e63b267 100644 --- a/src/objects/dictionary.h +++ b/src/objects/dictionary.h @@ -112,7 +112,7 @@ class NameDictionaryShape : public BaseDictionaryShape> { static inline uint32_t Hash(Isolate* isolate, Handle key); static inline uint32_t HashForObject(Isolate* isolate, Object* object); static inline Handle AsHandle(Isolate* isolate, Handle key); - static const int kPrefixSize = 2; + static const int kPrefixSize = 1; static const int kEntrySize = 3; static const int kEntryValueIndex = 1; static const bool kNeedsHoleCheck = false; @@ -125,7 +125,6 @@ class BaseNameDictionary : public Dictionary { public: static const int kNextEnumerationIndexIndex = HashTableBase::kPrefixStartIndex; - static const int kObjectHashIndex = kNextEnumerationIndexIndex + 1; static const int kEntryValueIndex = 1; // Accessors for next enumeration index. @@ -138,16 +137,6 @@ class BaseNameDictionary : public Dictionary { return Smi::ToInt(this->get(kNextEnumerationIndexIndex)); } - void SetHash(int masked_hash) { - DCHECK_EQ(masked_hash & JSReceiver::kHashMask, masked_hash); - this->set(kObjectHashIndex, Smi::FromInt(masked_hash)); - } - - int Hash() const { - Object* hash_obj = this->get(kObjectHashIndex); - return Smi::ToInt(hash_obj); - } - // Creates a new dictionary. MUST_USE_RESULT static Handle New( Isolate* isolate, int at_least_space_for, @@ -182,10 +171,7 @@ class NameDictionary static const int kEntryDetailsIndex = 2; static const int kInitialCapacity = 2; - inline Name* NameAt(int entry); - inline void set_hash(int hash); - inline int hash() const; }; class GlobalDictionaryShape : public NameDictionaryShape { diff --git a/src/runtime/runtime-collections.cc b/src/runtime/runtime-collections.cc index 5bd4dddaf0..a43de82111 100644 --- a/src/runtime/runtime-collections.cc +++ b/src/runtime/runtime-collections.cc @@ -17,13 +17,6 @@ RUNTIME_FUNCTION(Runtime_TheHole) { return isolate->heap()->the_hole_value(); } -RUNTIME_FUNCTION(Runtime_GetExistingHash) { - SealHandleScope shs(isolate); - DCHECK_EQ(1, args.length()); - CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); - return object->GetHash(); -} - RUNTIME_FUNCTION(Runtime_GenericHash) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index f83830af6d..c760e8a796 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -90,7 +90,6 @@ namespace internal { #define FOR_EACH_INTRINSIC_COLLECTIONS(F) \ F(TheHole, 0, 1) \ F(GenericHash, 1, 1) \ - F(GetExistingHash, 1, 1) \ F(SetGrow, 1, 1) \ F(SetShrink, 1, 1) \ F(SetIteratorClone, 1, 1) \ diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 6f508368eb..ea2f0c2d71 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -4035,7 +4035,7 @@ THREADED_TEST(External) { CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map()); CHECK(ext->IsExternal()); CHECK(!CompileRun("new Set().add(this.ext)").IsEmpty()); - CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map()); + CHECK_NE(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map()); CHECK(ext->IsExternal()); } diff --git a/test/cctest/test-dictionary.cc b/test/cctest/test-dictionary.cc index 2ffff06a63..c66cccca06 100644 --- a/test/cctest/test-dictionary.cc +++ b/test/cctest/test-dictionary.cc @@ -84,7 +84,7 @@ static void TestHashMap(Handle table) { CHECK_EQ(table->NumberOfElements(), i + 1); CHECK_NE(table->FindEntry(key), HashMap::kNotFound); CHECK_EQ(table->Lookup(key), *value); - CHECK(JSReceiver::GetIdentityHash(isolate, *key)->IsSmi()); + CHECK(JSReceiver::GetIdentityHash(isolate, key)->IsSmi()); } // Keys never added to the map which already have an identity hash @@ -94,7 +94,7 @@ static void TestHashMap(Handle table) { CHECK(JSReceiver::GetOrCreateIdentityHash(isolate, key)->IsSmi()); CHECK_EQ(table->FindEntry(key), HashMap::kNotFound); CHECK_EQ(table->Lookup(key), CcTest::heap()->the_hole_value()); - CHECK(JSReceiver::GetIdentityHash(isolate, *key)->IsSmi()); + CHECK(JSReceiver::GetIdentityHash(isolate, key)->IsSmi()); } // Keys that don't have an identity hash should not be found and also @@ -102,7 +102,7 @@ static void TestHashMap(Handle table) { for (int i = 0; i < 100; i++) { Handle key = factory->NewJSArray(7); CHECK_EQ(table->Lookup(key), CcTest::heap()->the_hole_value()); - Object* identity_hash = JSReceiver::GetIdentityHash(isolate, *key); + Object* identity_hash = JSReceiver::GetIdentityHash(isolate, key); CHECK_EQ(CcTest::heap()->undefined_value(), identity_hash); } } @@ -155,7 +155,7 @@ static void TestHashSet(Handle table) { table = HashSet::Add(table, key); CHECK_EQ(table->NumberOfElements(), i + 2); CHECK(table->Has(isolate, key)); - CHECK(JSReceiver::GetIdentityHash(isolate, *key)->IsSmi()); + CHECK(JSReceiver::GetIdentityHash(isolate, key)->IsSmi()); } // Keys never added to the map which already have an identity hash @@ -164,7 +164,7 @@ static void TestHashSet(Handle table) { Handle key = factory->NewJSArray(7); CHECK(JSReceiver::GetOrCreateIdentityHash(isolate, key)->IsSmi()); CHECK(!table->Has(isolate, key)); - CHECK(JSReceiver::GetIdentityHash(isolate, *key)->IsSmi()); + CHECK(JSReceiver::GetIdentityHash(isolate, key)->IsSmi()); } // Keys that don't have an identity hash should not be found and also @@ -172,7 +172,7 @@ static void TestHashSet(Handle table) { for (int i = 0; i < 100; i++) { Handle key = factory->NewJSArray(7); CHECK(!table->Has(isolate, key)); - Object* identity_hash = JSReceiver::GetIdentityHash(isolate, *key); + Object* identity_hash = JSReceiver::GetIdentityHash(isolate, key); CHECK_EQ(CcTest::heap()->undefined_value(), identity_hash); } } @@ -267,15 +267,15 @@ static void TestHashSetCausesGC(Handle table) { #ifdef DEBUG -template -static void TestHashMapDoesNotCauseGC(Handle table) { +template +static void TestHashMapCausesGC(Handle table) { Isolate* isolate = CcTest::i_isolate(); Factory* factory = isolate->factory(); Handle key = factory->NewJSArray(0); - // Even though we simulate a full heap, generating an identity hash - // code in subsequent calls will not request GC. + // Simulate a full heap so that generating an identity hash code + // in subsequent calls will request GC. heap::SimulateFullSpace(CcTest::heap()->new_space()); heap::SimulateFullSpace(CcTest::heap()->old_space()); @@ -285,7 +285,7 @@ static void TestHashMapDoesNotCauseGC(Handle table) { // Calling Put() should request GC by returning a failure. int gc_count = isolate->heap()->gc_count(); HashMap::Put(table, key, key); - CHECK(gc_count == isolate->heap()->gc_count()); + CHECK(gc_count < isolate->heap()->gc_count()); } @@ -294,7 +294,7 @@ TEST(ObjectHashTableCausesGC) { LocalContext context; v8::HandleScope scope(context->GetIsolate()); Isolate* isolate = CcTest::i_isolate(); - TestHashMapDoesNotCauseGC(ObjectHashTable::New(isolate, 1)); + TestHashMapCausesGC(ObjectHashTable::New(isolate, 1)); } #endif diff --git a/test/cctest/test-orderedhashtable.cc b/test/cctest/test-orderedhashtable.cc index cf1e29b471..e17a62dbd2 100644 --- a/test/cctest/test-orderedhashtable.cc +++ b/test/cctest/test-orderedhashtable.cc @@ -13,9 +13,17 @@ static Isolate* GetIsolateFrom(LocalContext* context) { return reinterpret_cast((*context)->GetIsolate()); } -void CopyHashCode(Handle from, Handle to) { - int hash = Smi::ToInt(from->GetHash()); - to->SetIdentityHash(hash); +void CopyHashCode(Isolate* isolate, Handle from, + Handle to) { + Handle hash_code_symbol = isolate->factory()->hash_code_symbol(); + Handle hash = + Handle::cast(JSObject::GetDataProperty(from, hash_code_symbol)); + + LookupIterator it(to, hash_code_symbol, to, LookupIterator::OWN); + CHECK(to->AddDataProperty( + &it, hash, NONE, v8::internal::AccessCheckInfo::THROW_ON_ERROR, + v8::internal::AccessCheckInfo::CERTAINLY_NOT_STORE_FROM_KEYED) + .IsJust()); } void Verify(Handle obj) { @@ -205,7 +213,7 @@ TEST(SmallOrderedHashSetDuplicateHashCode) { CHECK(set->HasKey(isolate, key1)); Handle key2 = factory->NewJSObjectWithNullProto(); - CopyHashCode(key1, key2); + CopyHashCode(isolate, key1, key2); set = SmallOrderedHashSet::Add(set, key2); Verify(set); @@ -230,9 +238,16 @@ TEST(SmallOrderedHashMapDuplicateHashCode) { CHECK_EQ(1, map->NumberOfElements()); CHECK(map->HasKey(isolate, key1)); - Handle key2 = factory->NewJSObjectWithNullProto(); - CopyHashCode(key1, key2); + Handle hash_code_symbol = isolate->factory()->hash_code_symbol(); + Handle hash = + Handle::cast(JSObject::GetDataProperty(key1, hash_code_symbol)); + Handle key2 = factory->NewJSObjectWithNullProto(); + LookupIterator it(key2, hash_code_symbol, key2, LookupIterator::OWN); + CHECK(key2->AddDataProperty( + &it, hash, NONE, v8::internal::AccessCheckInfo::THROW_ON_ERROR, + v8::internal::AccessCheckInfo::CERTAINLY_NOT_STORE_FROM_KEYED) + .IsJust()); CHECK(!key1->SameValue(*key2)); Object* hash1 = key1->GetHash(); Object* hash2 = key2->GetHash(); @@ -584,7 +599,7 @@ TEST(OrderedHashMapDuplicateHashCode) { CHECK(OrderedHashMap::HasKey(isolate, *map, *key1)); Handle key2 = factory->NewJSObjectWithNullProto(); - CopyHashCode(key1, key2); + CopyHashCode(isolate, key1, key2); map = OrderedHashMap::Add(map, key2, value); Verify(map); @@ -734,7 +749,7 @@ TEST(OrderedHashMapDuplicateHashCodeDeletion) { CHECK(OrderedHashMap::HasKey(isolate, *map, *key1)); Handle key2 = factory->NewJSObjectWithNullProto(); - CopyHashCode(key1, key2); + CopyHashCode(isolate, key1, key2); // We shouldn't be able to delete the key! CHECK(!OrderedHashMap::Delete(isolate, *map, *key2)); @@ -883,7 +898,7 @@ TEST(OrderedHashSetDuplicateHashCodeDeletion) { CHECK(OrderedHashSet::HasKey(isolate, *set, *key1)); Handle key2 = factory->NewJSObjectWithNullProto(); - CopyHashCode(key1, key2); + CopyHashCode(isolate, key1, key2); // We shouldn't be able to delete the key! CHECK(!OrderedHashSet::Delete(isolate, *set, *key2));