Revert "[runtime] Store hash code in length field"
This reverts commit decf5750c6
.
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 <gsathya@chromium.org>
> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> 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 <gsathya@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47260}
This commit is contained in:
parent
decf5750c6
commit
35f149e1d8
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -1152,18 +1152,9 @@ Node* CodeStubAssembler::TaggedDoesntHaveInstanceType(Node* any_tagged,
|
||||
MachineRepresentation::kBit);
|
||||
}
|
||||
|
||||
TNode<HeapObject> CodeStubAssembler::LoadFastProperties(
|
||||
TNode<HeapObject> CodeStubAssembler::LoadProperties(
|
||||
SloppyTNode<JSObject> object) {
|
||||
Node* properties = LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
|
||||
return SelectTaggedConstant<HeapObject>(
|
||||
TaggedIsSmi(properties), EmptyFixedArrayConstant(), properties);
|
||||
}
|
||||
|
||||
TNode<HeapObject> CodeStubAssembler::LoadSlowProperties(
|
||||
SloppyTNode<JSObject> object) {
|
||||
Node* properties = LoadObjectField(object, JSObject::kPropertiesOrHashOffset);
|
||||
return SelectTaggedConstant<HeapObject>(
|
||||
TaggedIsSmi(properties), EmptyPropertyDictionaryConstant(), properties);
|
||||
return CAST(LoadObjectField(object, JSObject::kPropertiesOrHashOffset));
|
||||
}
|
||||
|
||||
TNode<FixedArrayBase> 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<NameDictionary>(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<GlobalDictionary>(
|
||||
@ -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);
|
||||
|
||||
|
@ -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<HeapObject> LoadSlowProperties(SloppyTNode<JSObject> object);
|
||||
TNode<HeapObject> LoadFastProperties(SloppyTNode<JSObject> object);
|
||||
TNode<HeapObject> LoadProperties(SloppyTNode<JSObject> object);
|
||||
// Load the elements backing store of a JSObject.
|
||||
TNode<FixedArrayBase> LoadElements(SloppyTNode<JSObject> object);
|
||||
// Load the length of a JSArray instance.
|
||||
|
@ -54,10 +54,10 @@ FieldAccess AccessBuilder::ForHeapNumberValue() {
|
||||
|
||||
|
||||
// static
|
||||
FieldAccess AccessBuilder::ForJSObjectPropertiesOrHash() {
|
||||
FieldAccess AccessBuilder::ForJSObjectProperties() {
|
||||
FieldAccess access = {kTaggedBase, JSObject::kPropertiesOrHashOffset,
|
||||
MaybeHandle<Name>(), MaybeHandle<Map>(),
|
||||
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<Name>(), MaybeHandle<Map>(),
|
||||
Type::SignedSmall(), MachineType::TaggedSigned(),
|
||||
// TODO(gsathya): Update the value range once we add the hash code.
|
||||
FieldAccess access = {kTaggedBase,
|
||||
PropertyArray::kLengthOffset,
|
||||
MaybeHandle<Name>(),
|
||||
MaybeHandle<Map>(),
|
||||
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<Name>(),
|
||||
MaybeHandle<Map>(),
|
||||
Type::SignedSmall(),
|
||||
MachineType::TaggedSigned(),
|
||||
kNoWriteBarrier};
|
||||
return access;
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -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);
|
||||
|
@ -303,8 +303,8 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> 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);
|
||||
|
@ -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<JSArray> boilerplate_array = Handle<JSArray>::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()));
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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 =
|
||||
|
@ -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) \
|
||||
|
@ -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) \
|
||||
|
@ -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<LoadHandler::IsDoubleBits>(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<NameDictionary>(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<NameDictionary>(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<StoreHandler::FieldOffsetBits>(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<NameDictionary>(properties, p->name, &dictionary_found,
|
||||
&var_name_index,
|
||||
&lookup_prototype_chain);
|
||||
|
@ -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<NameDictionary>(properties, p->name, &dictionary_found,
|
||||
&var_name_index, ¬_found);
|
||||
BIND(&dictionary_found);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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<bool> JSReceiver::HasProperty(Handle<JSReceiver> object,
|
||||
Handle<Name> name) {
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(object->GetIsolate(),
|
||||
@ -5716,10 +5701,12 @@ Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate,
|
||||
isolate, Handle<JSObject>::cast(object));
|
||||
}
|
||||
|
||||
Object* JSReceiver::GetIdentityHash(Isolate* isolate, JSReceiver* receiver) {
|
||||
Object* JSReceiver::GetIdentityHash(Isolate* isolate,
|
||||
Handle<JSReceiver> receiver) {
|
||||
return receiver->IsJSProxy()
|
||||
? JSProxy::GetIdentityHash(JSProxy::cast(receiver))
|
||||
: JSObject::GetIdentityHash(isolate, JSObject::cast(receiver));
|
||||
? JSProxy::GetIdentityHash(Handle<JSProxy>::cast(receiver))
|
||||
: JSObject::GetIdentityHash(isolate,
|
||||
Handle<JSObject>::cast(receiver));
|
||||
}
|
||||
|
||||
|
||||
|
111
src/objects.cc
111
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> object) {
|
||||
@ -6257,74 +6257,6 @@ Handle<SeededNumberDictionary> 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 <typename ProxyType>
|
||||
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<JSObject> 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<Name> 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<JSGlobalProxy>::cast(object));
|
||||
}
|
||||
|
||||
Object* hash_obj = JSObject::GetIdentityHash(isolate, *object);
|
||||
if (hash_obj != isolate->heap()->undefined_value()) {
|
||||
return Smi::cast(hash_obj);
|
||||
Handle<Name> 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<JSProxy> proxy) {
|
||||
return proxy->hash();
|
||||
}
|
||||
|
||||
Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
|
||||
return GetOrCreateIdentityHashHelper(isolate, proxy);
|
||||
@ -17405,6 +17334,7 @@ Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> set,
|
||||
Handle<Object> 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<Derived> BaseNameDictionary<Derived, Shape>::New(
|
||||
DCHECK_LE(0, at_least_space_for);
|
||||
Handle<Derived> dict = Dictionary<Derived, Shape>::New(
|
||||
isolate, at_least_space_for, pretenure, capacity_option);
|
||||
dict->SetHash(PropertyArray::kNoHashSentinel);
|
||||
dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
|
||||
return dict;
|
||||
}
|
||||
|
129
src/objects.h
129
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<kHeaderSize> 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<JSReceiver> 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<JSReceiver> 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<FixedArray> OwnPropertyKeys(
|
||||
Handle<JSReceiver> object);
|
||||
@ -2221,8 +2158,6 @@ class JSReceiver: public HeapObject {
|
||||
MUST_USE_RESULT static MaybeHandle<FixedArray> GetOwnEntries(
|
||||
Handle<JSReceiver> 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<JSObject> object);
|
||||
|
||||
static Smi* GetOrCreateIdentityHash(Isolate* isolate,
|
||||
Handle<JSObject> 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<kHeaderSize> 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 <SearchMode search_mode, typename T>
|
||||
@ -6355,7 +6338,7 @@ class JSProxy: public JSReceiver {
|
||||
// No weak fields.
|
||||
typedef BodyDescriptor BodyDescriptorWeak;
|
||||
|
||||
static Object* GetIdentityHash(JSProxy* receiver);
|
||||
static Object* GetIdentityHash(Handle<JSProxy> receiver);
|
||||
|
||||
static Smi* GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy);
|
||||
|
||||
|
@ -112,7 +112,7 @@ class NameDictionaryShape : public BaseDictionaryShape<Handle<Name>> {
|
||||
static inline uint32_t Hash(Isolate* isolate, Handle<Name> key);
|
||||
static inline uint32_t HashForObject(Isolate* isolate, Object* object);
|
||||
static inline Handle<Object> AsHandle(Isolate* isolate, Handle<Name> 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<Derived, Shape> {
|
||||
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<Derived, Shape> {
|
||||
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<Derived> 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 {
|
||||
|
@ -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());
|
||||
|
@ -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) \
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ static void TestHashMap(Handle<HashMap> 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<HashMap> 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<HashMap> table) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Handle<JSReceiver> 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<HashSet> 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<HashSet> table) {
|
||||
Handle<JSReceiver> 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<HashSet> table) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Handle<JSReceiver> 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<HashSet> table) {
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
template <class HashMap>
|
||||
static void TestHashMapDoesNotCauseGC(Handle<HashMap> table) {
|
||||
template<class HashMap>
|
||||
static void TestHashMapCausesGC(Handle<HashMap> table) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Factory* factory = isolate->factory();
|
||||
|
||||
Handle<JSObject> 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<HashMap> 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
|
||||
|
||||
|
@ -13,9 +13,17 @@ static Isolate* GetIsolateFrom(LocalContext* context) {
|
||||
return reinterpret_cast<Isolate*>((*context)->GetIsolate());
|
||||
}
|
||||
|
||||
void CopyHashCode(Handle<JSReceiver> from, Handle<JSReceiver> to) {
|
||||
int hash = Smi::ToInt(from->GetHash());
|
||||
to->SetIdentityHash(hash);
|
||||
void CopyHashCode(Isolate* isolate, Handle<JSReceiver> from,
|
||||
Handle<JSReceiver> to) {
|
||||
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
|
||||
Handle<Smi> hash =
|
||||
Handle<Smi>::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<HeapObject> obj) {
|
||||
@ -205,7 +213,7 @@ TEST(SmallOrderedHashSetDuplicateHashCode) {
|
||||
CHECK(set->HasKey(isolate, key1));
|
||||
|
||||
Handle<JSObject> 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<JSObject> key2 = factory->NewJSObjectWithNullProto();
|
||||
CopyHashCode(key1, key2);
|
||||
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
|
||||
Handle<Smi> hash =
|
||||
Handle<Smi>::cast(JSObject::GetDataProperty(key1, hash_code_symbol));
|
||||
|
||||
Handle<JSObject> 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<JSObject> 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<JSObject> 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<JSObject> 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));
|
||||
|
Loading…
Reference in New Issue
Block a user