[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}
This commit is contained in:
Sathya Gunasekaran 2017-08-09 11:21:51 -07:00 committed by Commit Bot
parent d8e37c32f3
commit decf5750c6
27 changed files with 363 additions and 226 deletions

View File

@ -623,14 +623,14 @@ Node* ConstructorBuiltinsAssembler::EmitFastCloneShallowObject(
{
Comment("Copy dictionary properties");
var_properties.Bind(
CopyNameDictionary(LoadProperties(boilerplate), call_runtime));
CopyNameDictionary(LoadSlowProperties(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 = LoadProperties(boilerplate);
Node* boilerplate_properties = LoadFastProperties(boilerplate);
GotoIfNot(IsEmptyFixedArray(boilerplate_properties), call_runtime);
var_properties.Bind(EmptyFixedArrayConstant());
Goto(&done);

View File

@ -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 = LoadProperties(receiver);
Node* properties = LoadSlowProperties(receiver);
Node* length = LoadFixedArrayElement(
properties, NameDictionary::kNumberOfElementsIndex);
GotoIfNot(WordEqual(length, SmiConstant(0)), use_runtime);

View File

@ -460,7 +460,7 @@ TF_BUILTIN(DeleteProperty, DeletePropertyBaseAssembler) {
BIND(&dictionary);
{
Node* properties = LoadProperties(receiver);
Node* properties = LoadSlowProperties(receiver);
DeleteDictionaryProperty(receiver, properties, unique, context,
&dont_delete, &if_notfound);
}

View File

@ -78,7 +78,7 @@ class ProxiesCodeStubAssembler : public CodeStubAssembler {
Node* proxy = Allocate(JSProxy::kSize);
StoreMapNoWriteBarrier(proxy, map.value());
StoreObjectFieldRoot(proxy, JSProxy::kPropertiesOrHashOffset,
Heap::kEmptyPropertiesDictionaryRootIndex);
Heap::kEmptyPropertyDictionaryRootIndex);
StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kTargetOffset, target);
StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHandlerOffset, handler);
StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHashOffset,

View File

@ -1152,9 +1152,18 @@ Node* CodeStubAssembler::TaggedDoesntHaveInstanceType(Node* any_tagged,
MachineRepresentation::kBit);
}
TNode<HeapObject> CodeStubAssembler::LoadProperties(
TNode<HeapObject> CodeStubAssembler::LoadFastProperties(
SloppyTNode<JSObject> object) {
return CAST(LoadObjectField(object, JSObject::kPropertiesOrHashOffset));
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);
}
TNode<FixedArrayBase> CodeStubAssembler::LoadElements(
@ -2248,6 +2257,9 @@ 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);
@ -2488,18 +2500,6 @@ 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 = LoadProperties(object);
Node* dictionary = LoadSlowProperties(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 = LoadProperties(object);
Node* dictionary = LoadSlowProperties(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 = LoadProperties(object);
Node* properties = LoadFastProperties(object);
field_index = IntPtrSub(field_index, inobject_properties);
Node* value = LoadFixedArrayElement(properties, field_index);

View File

@ -28,6 +28,8 @@ 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) \
@ -442,7 +444,8 @@ 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> LoadProperties(SloppyTNode<JSObject> object);
TNode<HeapObject> LoadSlowProperties(SloppyTNode<JSObject> object);
TNode<HeapObject> LoadFastProperties(SloppyTNode<JSObject> object);
// Load the elements backing store of a JSObject.
TNode<FixedArrayBase> LoadElements(SloppyTNode<JSObject> object);
// Load the length of a JSArray instance.

View File

@ -54,10 +54,10 @@ FieldAccess AccessBuilder::ForHeapNumberValue() {
// static
FieldAccess AccessBuilder::ForJSObjectProperties() {
FieldAccess AccessBuilder::ForJSObjectPropertiesOrHash() {
FieldAccess access = {kTaggedBase, JSObject::kPropertiesOrHashOffset,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::Internal(), MachineType::TaggedPointer(),
Type::Any(), MachineType::AnyTagged(),
kPointerWriteBarrier};
return access;
}
@ -477,14 +477,11 @@ FieldAccess AccessBuilder::ForFixedArrayLength() {
}
// static
// TODO(gsathya): Rename this to PropertyArrayLengthAndHash.
FieldAccess AccessBuilder::ForPropertyArrayLength() {
// 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(),
FieldAccess access = {kTaggedBase, PropertyArray::kLengthOffset,
MaybeHandle<Name>(), MaybeHandle<Map>(),
Type::SignedSmall(), MachineType::TaggedSigned(),
kNoWriteBarrier};
return access;
}
@ -1115,6 +1112,19 @@ 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

View File

@ -39,7 +39,7 @@ class V8_EXPORT_PRIVATE AccessBuilder final
static FieldAccess ForHeapNumberValue();
// Provides access to JSObject::properties() field.
static FieldAccess ForJSObjectProperties();
static FieldAccess ForJSObjectPropertiesOrHash();
// Provides access to JSObject::elements() field.
static FieldAccess ForJSObjectElements();
@ -303,6 +303,7 @@ 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);

View File

@ -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::ForJSObjectProperties()), value,
jsgraph()->EmptyFixedArrayConstant(), effect, control);
simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()),
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::ForJSObjectProperties()), value,
jsgraph()->EmptyFixedArrayConstant(), effect, control);
simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()),
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::ForJSObjectProperties()), value,
jsgraph()->EmptyFixedArrayConstant(), effect, control);
simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()),
value, jsgraph()->EmptyFixedArrayConstant(), effect, control);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
jsgraph()->EmptyFixedArrayConstant(), effect, control);
@ -2345,9 +2345,15 @@ 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.
for (int index = NameDictionary::kNextEnumerationIndexIndex + 1;
index < length; index++) {
STATIC_ASSERT(NameDictionary::kElementsStartIndex ==
NameDictionary::kObjectHashIndex + 1);
for (int index = NameDictionary::kElementsStartIndex; index < length;
index++) {
effect = graph()->NewNode(
simplified()->StoreField(
AccessBuilder::ForFixedArraySlot(index, kNoWriteBarrier)),
@ -2372,8 +2378,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::ForJSObjectProperties()), value,
properties, effect, control);
simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()),
value, properties, effect, control);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
jsgraph()->EmptyFixedArrayConstant(), effect, control);
@ -2616,8 +2622,8 @@ Reduction JSBuiltinReducer::ReduceStringIterator(Node* node) {
effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
value, map, effect, control);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value,
jsgraph()->EmptyFixedArrayConstant(), effect, control);
simplified()->StoreField(AccessBuilder::ForJSObjectPropertiesOrHash()),
value, jsgraph()->EmptyFixedArrayConstant(), effect, control);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
jsgraph()->EmptyFixedArrayConstant(), effect, control);

View File

@ -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::ForJSObjectProperties(),
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), empty_fixed_array);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(),
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
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::ForJSObjectProperties(), properties);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(), properties);
builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(), 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::ForJSObjectProperties(),
builder.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
handle(boilerplate->raw_properties_or_hash(), isolate()));
builder.Store(AccessBuilder::ForJSObjectElements(),
handle(boilerplate->elements(), isolate()));

View File

@ -1654,7 +1654,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
Node* storage = receiver;
if (!field_index.is_inobject()) {
storage = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
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::ForJSObjectProperties();
field_access = AccessBuilder::ForJSObjectPropertiesOrHash();
value = storage;
storage = receiver;
}
@ -2242,8 +2242,17 @@ 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);
@ -2252,13 +2261,12 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
jsgraph()->PropertyArrayMapConstant(), effect, control);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForPropertyArrayLength()),
new_properties, jsgraph()->Constant(new_length), effect, control);
new_properties, new_length_and_hash, 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);
}

View File

@ -224,7 +224,7 @@ Node* PropertyAccessBuilder::BuildLoadDataField(
Node* storage = receiver;
if (!field_index.is_inobject()) {
storage = *effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectProperties()),
simplified()->LoadField(AccessBuilder::ForJSObjectPropertiesOrHash()),
storage, *effect, *control);
}
FieldAccess field_access = {

View File

@ -83,11 +83,6 @@ 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 =

View File

@ -221,7 +221,6 @@
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) \

View File

@ -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, EmptyPropertiesDictionary) \
V(NameDictionary, empty_property_dictionary, EmptyPropertyDictionary) \
V(NameDictionary, public_symbol_table, PublicSymbolTable) \
V(NameDictionary, api_symbol_table, ApiSymbolTable) \
V(NameDictionary, api_private_symbol_table, ApiPrivateSymbolTable) \

View File

@ -195,7 +195,7 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
BIND(&out_of_object);
{
Label is_double(this);
Node* properties = LoadProperties(holder);
Node* properties = LoadFastProperties(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 = LoadProperties(holder);
Node* properties = LoadSlowProperties(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 = LoadProperties(p->receiver);
Node* properties = LoadSlowProperties(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 = LoadProperties(holder);
Node* properties = LoadSlowProperties(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 = LoadProperties(p->receiver);
Node* properties = LoadSlowProperties(p->receiver);
VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label found(this, &var_name_index), not_found(this);
@ -1050,8 +1050,14 @@ void AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
ParameterMode mode = OptimalParameterMode();
Node* properties = LoadProperties(object);
Node* length = TaggedToParameter(LoadPropertyArrayLength(properties), mode);
// 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);
// Previous property deletion could have left behind unused backing store
// capacity even for a map that think it doesn't have any unused fields.
@ -1085,7 +1091,16 @@ void AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
CopyPropertyArrayValues(properties, new_properties, length,
SKIP_WRITE_BARRIER, mode);
// TODO(gsathya): Update hash code here.
// 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));
StoreObjectField(object, JSObject::kPropertiesOrHashOffset, new_properties);
Comment("] Extend storage");
Goto(&done);
@ -1101,7 +1116,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 = LoadProperties(object);
property_storage = LoadFastProperties(object);
}
Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word);
@ -1402,7 +1417,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 = LoadProperties(object);
Node* properties = LoadSlowProperties(object);
// Ensure the property does not exist in a dictionary-mode object.
VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label done(this);
@ -1535,7 +1550,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label dictionary_found(this, &var_name_index);
Node* properties = LoadProperties(receiver);
Node* properties = LoadSlowProperties(receiver);
NameDictionaryLookup<NameDictionary>(properties, p->name, &dictionary_found,
&var_name_index,
&lookup_prototype_chain);

View File

@ -784,7 +784,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&data_property);
{
CheckForAssociatedProtector(p->name, slow);
Node* properties = LoadProperties(receiver);
Node* properties = LoadFastProperties(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 = LoadProperties(receiver);
Node* properties = LoadSlowProperties(receiver);
NameDictionaryLookup<NameDictionary>(properties, p->name, &dictionary_found,
&var_name_index, &not_found);
BIND(&dictionary_found);

View File

@ -11,7 +11,6 @@
// -------------------------------------------------------------------
// Imports
var hashCodeSymbol = utils.ImportNow("hash_code_symbol");
var GlobalWeakMap = global.WeakMap;
var GlobalWeakSet = global.WeakSet;
var MathRandom = global.Math.random;
@ -20,8 +19,7 @@ var MathRandom = global.Math.random;
function GetExistingHash(key) {
if (IS_RECEIVER(key) && !IS_PROXY(key) && !IS_GLOBAL(key)) {
var hash = GET_PRIVATE(key, hashCodeSymbol);
return hash;
return %GetExistingHash(key);
}
return %GenericHash(key);
}
@ -29,13 +27,7 @@ function GetExistingHash(key) {
function GetHash(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;
return %GenericHash(key);
}
%SetForceInlineFlag(GetHash);

View File

@ -2681,9 +2681,9 @@ SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
SYNCHRONIZED_SMI_ACCESSORS(FixedArrayBase, length, kLengthOffset)
int PropertyArray::length() const {
Object* value = READ_FIELD(this, kLengthOffset);
int len = Smi::ToInt(value);
return len & kLengthMask;
Object* value_obj = READ_FIELD(this, kLengthOffset);
int value = Smi::ToInt(value_obj);
return value & kLengthMask;
}
void PropertyArray::initialize_length(int len) {
@ -2693,9 +2693,23 @@ void PropertyArray::initialize_length(int len) {
}
int PropertyArray::synchronized_length() const {
Object* value = ACQUIRE_READ_FIELD(this, kLengthOffset);
int len = Smi::ToInt(value);
return len & kLengthMask;
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));
}
SMI_ACCESSORS(FreeSpace, size, kSizeOffset)
@ -5459,7 +5473,7 @@ bool JSObject::HasIndexedInterceptor() {
void JSGlobalObject::set_global_dictionary(GlobalDictionary* dictionary) {
DCHECK(IsJSGlobalObject());
return SetProperties(dictionary);
set_raw_properties_or_hash(dictionary);
}
GlobalDictionary* JSGlobalObject::global_dictionary() {
@ -5588,7 +5602,13 @@ bool JSReceiver::HasFastProperties() const {
NameDictionary* JSReceiver::property_dictionary() const {
DCHECK(!IsJSGlobalObject());
DCHECK(!HasFastProperties());
return NameDictionary::cast(raw_properties_or_hash());
Object* prop = raw_properties_or_hash();
if (prop->IsSmi()) {
return GetHeap()->empty_property_dictionary();
}
return NameDictionary::cast(prop);
}
// TODO(gsathya): Pass isolate directly to this function and access
@ -5604,11 +5624,6 @@ 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(),
@ -5701,12 +5716,10 @@ Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate,
isolate, Handle<JSObject>::cast(object));
}
Object* JSReceiver::GetIdentityHash(Isolate* isolate,
Handle<JSReceiver> receiver) {
Object* JSReceiver::GetIdentityHash(Isolate* isolate, JSReceiver* receiver) {
return receiver->IsJSProxy()
? JSProxy::GetIdentityHash(Handle<JSProxy>::cast(receiver))
: JSObject::GetIdentityHash(isolate,
Handle<JSObject>::cast(receiver));
? JSProxy::GetIdentityHash(JSProxy::cast(receiver))
: JSObject::GetIdentityHash(isolate, JSObject::cast(receiver));
}

View File

@ -2322,7 +2322,7 @@ Object* Object::GetHash() {
DCHECK(IsJSReceiver());
JSReceiver* receiver = JSReceiver::cast(this);
Isolate* isolate = receiver->GetIsolate();
return JSReceiver::GetIdentityHash(isolate, handle(receiver, isolate));
return JSReceiver::GetIdentityHash(isolate, receiver);
}
Smi* Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
@ -6257,6 +6257,74 @@ 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,
@ -6270,12 +6338,17 @@ static Smi* GetOrCreateIdentityHashHelper(Isolate* isolate,
}
// static
Object* JSObject::GetIdentityHash(Isolate* isolate, Handle<JSObject> object) {
Object* JSObject::GetIdentityHash(Isolate* isolate, JSObject* object) {
if (object->IsJSGlobalProxy()) {
return JSGlobalProxy::cast(*object)->hash();
return JSGlobalProxy::cast(object)->hash();
}
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
return *JSReceiver::GetDataProperty(object, hash_code_symbol);
int hash = GetIdentityHashHelper(isolate, object);
if (hash == PropertyArray::kNoHashSentinel) {
return isolate->heap()->undefined_value();
}
return Smi::FromInt(hash);
}
// static
@ -6286,25 +6359,23 @@ Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate,
Handle<JSGlobalProxy>::cast(object));
}
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);
Object* hash_obj = JSObject::GetIdentityHash(isolate, *object);
if (hash_obj != isolate->heap()->undefined_value()) {
return Smi::cast(hash_obj);
}
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;
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);
}
// static
Object* JSProxy::GetIdentityHash(Handle<JSProxy> proxy) {
return proxy->hash();
}
Object* JSProxy::GetIdentityHash(JSProxy* proxy) { return proxy->hash(); }
Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy) {
return GetOrCreateIdentityHashHelper(isolate, proxy);
@ -17334,7 +17405,6 @@ 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);
@ -17653,6 +17723,7 @@ 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;
}

View File

@ -1945,6 +1945,62 @@ 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 {
@ -1961,12 +2017,13 @@ class JSReceiver: public HeapObject {
// Gets slow properties for non-global objects.
inline NameDictionary* property_dictionary() const;
inline void SetProperties(HeapObject* properties);
void SetProperties(HeapObject* properties);
// There are four possible value for the properties offset.
// 1) EmptyFixedArray -- This is the standard placeholder.
// There are five possible values for the properties offset.
// 1) EmptyFixedArray/EmptyPropertyDictionary - This is the standard
// placeholder.
//
// 2) TODO(gsathya): Smi -- This is the hash code of the object.
// 2) 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
@ -1974,6 +2031,9 @@ 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)
@ -2140,14 +2200,17 @@ 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,
Handle<JSReceiver> object);
static inline Object* GetIdentityHash(Isolate* isolate, 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);
@ -2158,6 +2221,8 @@ 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;
@ -2663,7 +2728,7 @@ class JSObject: public JSReceiver {
ElementsKind kind,
Object* object);
static Object* GetIdentityHash(Isolate* isolate, Handle<JSObject> object);
static Object* GetIdentityHash(Isolate* isolate, JSObject* object);
static Smi* GetOrCreateIdentityHash(Isolate* isolate,
Handle<JSObject> object);
@ -3041,54 +3106,6 @@ 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>
@ -6338,7 +6355,7 @@ class JSProxy: public JSReceiver {
// No weak fields.
typedef BodyDescriptor BodyDescriptorWeak;
static Object* GetIdentityHash(Handle<JSProxy> receiver);
static Object* GetIdentityHash(JSProxy* receiver);
static Smi* GetOrCreateIdentityHash(Isolate* isolate, Handle<JSProxy> proxy);

View File

@ -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 = 1;
static const int kPrefixSize = 2;
static const int kEntrySize = 3;
static const int kEntryValueIndex = 1;
static const bool kNeedsHoleCheck = false;
@ -125,6 +125,7 @@ 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.
@ -137,6 +138,16 @@ 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,
@ -171,7 +182,10 @@ 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 {

View File

@ -17,6 +17,13 @@ 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());

View File

@ -90,6 +90,7 @@ 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) \

View File

@ -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_NE(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
CHECK_EQ(i::HeapObject::cast(*obj)->map(), CcTest::heap()->external_map());
CHECK(ext->IsExternal());
}

View File

@ -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 TestHashMapCausesGC(Handle<HashMap> table) {
template <class HashMap>
static void TestHashMapDoesNotCauseGC(Handle<HashMap> table) {
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
Handle<JSObject> key = factory->NewJSArray(0);
// Simulate a full heap so that generating an identity hash code
// in subsequent calls will request GC.
// Even though we simulate a full heap, generating an identity hash
// code in subsequent calls will not request GC.
heap::SimulateFullSpace(CcTest::heap()->new_space());
heap::SimulateFullSpace(CcTest::heap()->old_space());
@ -285,7 +285,7 @@ static void TestHashMapCausesGC(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();
TestHashMapCausesGC(ObjectHashTable::New(isolate, 1));
TestHashMapDoesNotCauseGC(ObjectHashTable::New(isolate, 1));
}
#endif

View File

@ -13,17 +13,9 @@ static Isolate* GetIsolateFrom(LocalContext* context) {
return reinterpret_cast<Isolate*>((*context)->GetIsolate());
}
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 CopyHashCode(Handle<JSReceiver> from, Handle<JSReceiver> to) {
int hash = Smi::ToInt(from->GetHash());
to->SetIdentityHash(hash);
}
void Verify(Handle<HeapObject> obj) {
@ -213,7 +205,7 @@ TEST(SmallOrderedHashSetDuplicateHashCode) {
CHECK(set->HasKey(isolate, key1));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
CopyHashCode(isolate, key1, key2);
CopyHashCode(key1, key2);
set = SmallOrderedHashSet::Add(set, key2);
Verify(set);
@ -238,16 +230,9 @@ TEST(SmallOrderedHashMapDuplicateHashCode) {
CHECK_EQ(1, map->NumberOfElements());
CHECK(map->HasKey(isolate, key1));
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());
CopyHashCode(key1, key2);
CHECK(!key1->SameValue(*key2));
Object* hash1 = key1->GetHash();
Object* hash2 = key2->GetHash();
@ -599,7 +584,7 @@ TEST(OrderedHashMapDuplicateHashCode) {
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
CopyHashCode(isolate, key1, key2);
CopyHashCode(key1, key2);
map = OrderedHashMap::Add(map, key2, value);
Verify(map);
@ -749,7 +734,7 @@ TEST(OrderedHashMapDuplicateHashCodeDeletion) {
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
CopyHashCode(isolate, key1, key2);
CopyHashCode(key1, key2);
// We shouldn't be able to delete the key!
CHECK(!OrderedHashMap::Delete(isolate, *map, *key2));
@ -898,7 +883,7 @@ TEST(OrderedHashSetDuplicateHashCodeDeletion) {
CHECK(OrderedHashSet::HasKey(isolate, *set, *key1));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
CopyHashCode(isolate, key1, key2);
CopyHashCode(key1, key2);
// We shouldn't be able to delete the key!
CHECK(!OrderedHashSet::Delete(isolate, *set, *key2));