[es2015] Unify hash storage for JSProxy and JSGlobalProxy.

Have JSProxy and JSGlobalProxy use the properties or hash technology
like we use for all other JSReceivers. Also unify and simplify the
code dealing with these hashes.

Bug: v8:6344, v8:6911
Change-Id: Ic995639c74211ba6f33acd73428b8c6d95bf7919
Reviewed-on: https://chromium-review.googlesource.com/737833
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48930}
This commit is contained in:
Benedikt Meurer 2017-10-25 14:16:53 +02:00 committed by Commit Bot
parent bb56b7ecad
commit b1aaa6af5d
10 changed files with 71 additions and 151 deletions

View File

@ -29,6 +29,7 @@ class CollectionsBuiltinsAssembler : public CodeStubAssembler {
Node* AllocateJSCollectionIterator(Node* context, int map_index,
Node* collection);
Node* GetExistingHashForReceiver(Node* const receiver);
Node* GetHash(Node* const key);
Node* CallGetHashRaw(Node* const key);
Node* CallGetOrCreateHashRaw(Node* const key);
@ -471,31 +472,71 @@ Node* CollectionsBuiltinsAssembler::CallGetHashRaw(Node* const key) {
return SmiUntag(result);
}
Node* CollectionsBuiltinsAssembler::GetHash(Node* const key) {
VARIABLE(var_result, MachineType::PointerRepresentation());
Label if_jsobject(this), other(this), done(this);
Node* instance_type = LoadMapInstanceType(LoadMap(key));
Branch(IsJSObjectInstanceType(instance_type), &if_jsobject, &other);
Node* CollectionsBuiltinsAssembler::GetExistingHashForReceiver(
Node* const receiver) {
VARIABLE(var_hash, MachineType::PointerRepresentation());
Label done(this), if_smi(this), if_property_array(this),
if_property_dictionary(this), if_fixed_array(this);
BIND(&if_jsobject);
Node* properties_or_hash =
LoadObjectField(receiver, JSReceiver::kPropertiesOrHashOffset);
GotoIf(TaggedIsSmi(properties_or_hash), &if_smi);
Node* properties_instance_type = LoadInstanceType(properties_or_hash);
GotoIf(InstanceTypeEqual(properties_instance_type, PROPERTY_ARRAY_TYPE),
&if_property_array);
Branch(InstanceTypeEqual(properties_instance_type, HASH_TABLE_TYPE),
&if_property_dictionary, &if_fixed_array);
BIND(&if_fixed_array);
{
Node* hash = LoadHashForJSObject(key, instance_type);
// TODO(gsathya): Change all uses of -1 to PropertyArray::kNoHashSentinel.
var_result.Bind(SelectConstant(
Word32Equal(hash, Int32Constant(PropertyArray::kNoHashSentinel)),
IntPtrConstant(-1), ChangeInt32ToIntPtr(hash),
MachineType::PointerRepresentation()));
var_hash.Bind(IntPtrConstant(PropertyArray::kNoHashSentinel));
Goto(&done);
}
BIND(&other);
BIND(&if_smi);
{
var_result.Bind(CallGetHashRaw(key));
var_hash.Bind(SmiToWord(properties_or_hash));
Goto(&done);
}
BIND(&if_property_array);
{
Node* length_and_hash = LoadAndUntagObjectField(
properties_or_hash, PropertyArray::kLengthAndHashOffset);
var_hash.Bind(DecodeWord<PropertyArray::HashField>(length_and_hash));
Goto(&done);
}
BIND(&if_property_dictionary);
{
var_hash.Bind(SmiToWord(LoadFixedArrayElement(
properties_or_hash, NameDictionary::kObjectHashIndex)));
Goto(&done);
}
BIND(&done);
return var_result.value();
return var_hash.value();
}
Node* CollectionsBuiltinsAssembler::GetHash(Node* const key) {
VARIABLE(var_hash, MachineType::PointerRepresentation());
Label if_receiver(this), if_other(this), done(this);
Branch(IsJSReceiver(key), &if_receiver, &if_other);
BIND(&if_receiver);
{
var_hash.Bind(GetExistingHashForReceiver(key));
Goto(&done);
}
BIND(&if_other);
{
var_hash.Bind(CallGetHashRaw(key));
Goto(&done);
}
BIND(&done);
return var_hash.value();
}
void CollectionsBuiltinsAssembler::SameValueZeroSmi(Node* key_smi,
@ -590,6 +631,7 @@ void CollectionsBuiltinsAssembler::FindOrderedHashTableEntryForOtherKey(
Node* context, Node* table, Node* key, Variable* result, Label* entry_found,
Label* not_found) {
Node* hash = GetHash(key);
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(hash, IntPtrConstant(0)));
result->Bind(hash);
FindOrderedHashTableEntry<CollectionType>(
table, hash,
@ -972,8 +1014,8 @@ TF_BUILTIN(MapPrototypeSet, CollectionsBuiltinsAssembler) {
BIND(&not_found);
{
// If we have a hash code, we can start adding the new entry.
GotoIf(IntPtrGreaterThanOrEqual(entry_start_position_or_hash.value(),
IntPtrConstant(0)),
GotoIf(IntPtrGreaterThan(entry_start_position_or_hash.value(),
IntPtrConstant(0)),
&add_entry);
// Otherwise, go to runtime to compute the hash code.
@ -1138,8 +1180,8 @@ TF_BUILTIN(SetPrototypeAdd, CollectionsBuiltinsAssembler) {
BIND(&not_found);
{
// If we have a hash code, we can start adding the new entry.
GotoIf(IntPtrGreaterThanOrEqual(entry_start_position_or_hash.value(),
IntPtrConstant(0)),
GotoIf(IntPtrGreaterThan(entry_start_position_or_hash.value(),
IntPtrConstant(0)),
&add_entry);
// Otherwise, go to runtime to compute the hash code.
@ -1724,7 +1766,7 @@ TF_BUILTIN(WeakMapLookupHashIndex, CollectionsBuiltinsAssembler) {
Node* const hash = GetHash(key);
GotoIf(IntPtrLessThan(hash, IntPtrConstant(0)), &if_not_found);
GotoIf(WordEqual(hash, IntPtrConstant(0)), &if_not_found);
// See HashTable::FirstProbe().
Node* entry = WordAnd(hash, mask);

View File

@ -67,8 +67,6 @@ Node* ProxiesCodeStubAssembler::AllocateProxy(Node* target, Node* handler,
Heap::kEmptyPropertyDictionaryRootIndex);
StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kTargetOffset, target);
StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHandlerOffset, handler);
StoreObjectFieldNoWriteBarrier(proxy, JSProxy::kHashOffset,
UndefinedConstant());
return proxy;
}

View File

@ -1229,61 +1229,6 @@ Node* CodeStubAssembler::TaggedDoesntHaveInstanceType(Node* any_tagged,
MachineRepresentation::kBit);
}
TNode<Int32T> CodeStubAssembler::LoadHashForJSObject(
SloppyTNode<JSObject> jsobject, SloppyTNode<Int32T> instance_type) {
VARIABLE(var_hash, MachineRepresentation::kWord32);
Label if_global_proxy(this, Label::kDeferred);
GotoIf(IsJSGlobalProxyInstanceType(instance_type), &if_global_proxy);
Node* properties_or_hash =
LoadObjectField(jsobject, JSObject::kPropertiesOrHashOffset);
Label if_smi(this);
GotoIf(TaggedIsSmi(properties_or_hash), &if_smi);
Node* type = LoadInstanceType(properties_or_hash);
Label if_property_array(this), if_property_dictionary(this), done(this);
GotoIf(InstanceTypeEqual(type, PROPERTY_ARRAY_TYPE), &if_property_array);
GotoIf(InstanceTypeEqual(type, HASH_TABLE_TYPE), &if_property_dictionary);
var_hash.Bind(Int32Constant(PropertyArray::kNoHashSentinel));
Goto(&done);
BIND(&if_smi);
{
var_hash.Bind(SmiToWord32(properties_or_hash));
Goto(&done);
}
BIND(&if_property_array);
{
Node* length_and_hash_int32 = LoadAndUntagToWord32ObjectField(
properties_or_hash, PropertyArray::kLengthAndHashOffset);
var_hash.Bind(
DecodeWord32<PropertyArray::HashField>(length_and_hash_int32));
Goto(&done);
}
BIND(&if_property_dictionary);
{
var_hash.Bind(SmiToWord32(LoadFixedArrayElement(
properties_or_hash, NameDictionary::kObjectHashIndex)));
Goto(&done);
}
BIND(&if_global_proxy);
{
Node* hash = LoadObjectField(jsobject, JSGlobalProxy::kHashOffset);
var_hash.Bind(SelectConstant(TaggedIsSmi(hash), SmiToWord32(hash),
Int32Constant(PropertyArray::kNoHashSentinel),
MachineRepresentation::kWord32));
Goto(&done);
}
BIND(&done);
return UncheckedCast<Int32T>(var_hash.value());
}
TNode<HeapObject> CodeStubAssembler::LoadFastProperties(
SloppyTNode<JSObject> object) {
CSA_SLOW_ASSERT(this, Word32Not(IsDictionaryMap(LoadMap(object))));

View File

@ -473,9 +473,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
// Load the properties backing store of a JSObject.
TNode<HeapObject> LoadSlowProperties(SloppyTNode<JSObject> object);
TNode<HeapObject> LoadFastProperties(SloppyTNode<JSObject> object);
// Load the hash from the backing store of a JSObject.
TNode<Int32T> LoadHashForJSObject(SloppyTNode<JSObject> jsobject,
SloppyTNode<Int32T> instance_type);
// Load the elements backing store of a JSObject.
TNode<FixedArrayBase> LoadElements(SloppyTNode<JSObject> object);
// Load the length of a JSArray instance.

View File

@ -2477,7 +2477,6 @@ Handle<JSProxy> Factory::NewJSProxy(Handle<JSReceiver> target,
result->initialize_properties();
result->set_target(*target);
result->set_handler(*handler);
result->set_hash(*undefined_value(), SKIP_WRITE_BARRIER);
return result;
}
@ -2501,7 +2500,8 @@ void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
Handle<Map> old_map(object->map(), isolate());
// The proxy's hash should be retained across reinitialization.
Handle<Object> hash(object->hash(), isolate());
Handle<Object> raw_properties_or_hash(object->raw_properties_or_hash(),
isolate());
if (old_map->is_prototype_map()) {
map = Map::Copy(map, "CopyAsPrototypeForJSGlobalProxy");
@ -2515,9 +2515,6 @@ void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
DCHECK(map->instance_size() == old_map->instance_size());
DCHECK(map->instance_type() == old_map->instance_type());
// Allocate the backing storage for the properties.
Handle<FixedArray> properties = empty_fixed_array();
// In order to keep heap in consistent state there must be no allocations
// before object re-initialization is finished.
DisallowHeapAllocation no_allocation;
@ -2527,10 +2524,7 @@ void Factory::ReinitializeJSGlobalProxy(Handle<JSGlobalProxy> object,
Heap* heap = isolate()->heap();
// Reinitialize the object from the constructor map.
heap->InitializeJSObjectFromMap(*object, *properties, *map);
// Restore the saved hash.
object->set_hash(*hash);
heap->InitializeJSObjectFromMap(*object, *raw_properties_or_hash, *map);
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(

View File

@ -759,7 +759,6 @@ void JSGlobalProxy::JSGlobalProxyVerify() {
JSObjectVerify();
VerifyObjectField(JSGlobalProxy::kNativeContextOffset);
// Make sure that this object has no properties, elements.
CHECK_EQ(GetHeap()->empty_fixed_array(), raw_properties_or_hash());
CHECK_EQ(0, FixedArray::cast(elements())->length());
}
@ -1126,7 +1125,6 @@ void JSProxy::JSProxyVerify() {
Isolate* isolate = GetIsolate();
CHECK_EQ(target()->IsCallable(), map()->is_callable());
CHECK_EQ(target()->IsConstructor(), map()->is_constructor());
CHECK(hash()->IsSmi() || hash()->IsUndefined(isolate));
CHECK(map()->prototype()->IsNull(isolate));
// There should be no properties on a Proxy.
CHECK_EQ(0, map()->NumberOfOwnDescriptors());

View File

@ -3744,7 +3744,6 @@ ACCESSORS(JSGlobalObject, native_context, Context, kNativeContextOffset)
ACCESSORS(JSGlobalObject, global_proxy, JSObject, kGlobalProxyOffset)
ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset)
ACCESSORS(JSGlobalProxy, hash, Object, kHashOffset)
ACCESSORS(AccessorInfo, name, Object, kNameOffset)
SMI_ACCESSORS(AccessorInfo, flag, kFlagOffset)
@ -4229,7 +4228,6 @@ bool JSFunction::is_compiled() {
ACCESSORS(JSProxy, target, JSReceiver, kTargetOffset)
ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
ACCESSORS(JSProxy, hash, Object, kHashOffset)
bool JSProxy::IsRevoked() const { return !handler()->IsJSReceiver(); }
@ -4683,16 +4681,6 @@ inline int JSGlobalProxy::SizeWithEmbedderFields(int embedder_field_count) {
return kSize + embedder_field_count * kPointerSize;
}
Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) {
return IsJSProxy() ? JSProxy::cast(this)->GetOrCreateIdentityHash(isolate)
: JSObject::cast(this)->GetOrCreateIdentityHash(isolate);
}
Object* JSReceiver::GetIdentityHash(Isolate* isolate) {
return IsJSProxy() ? JSProxy::cast(this)->GetIdentityHash()
: JSObject::cast(this)->GetIdentityHash(isolate);
}
bool AccessorInfo::all_can_read() {
return BooleanBit::get(flag(), kAllCanReadBit);

View File

@ -925,8 +925,6 @@ void JSProxy::JSProxyPrint(std::ostream& os) { // NOLINT
target()->ShortPrint(os);
os << "\n - handler = ";
handler()->ShortPrint(os);
os << "\n - hash = ";
hash()->ShortPrint(os);
os << "\n";
}
@ -1186,7 +1184,6 @@ void JSGlobalProxy::JSGlobalProxyPrint(std::ostream& os) { // NOLINT
if (!GetIsolate()->bootstrapper()->IsActive()) {
os << "\n - native context = " << Brief(native_context());
}
os << "\n - hash = " << Brief(hash());
JSObjectPrintBody(os, this);
}

View File

@ -6499,22 +6499,8 @@ void JSReceiver::SetProperties(HeapObject* properties) {
set_raw_properties_or_hash(new_properties);
}
template <typename ProxyType>
Smi* GetOrCreateIdentityHashHelper(Isolate* isolate, ProxyType* proxy) {
Object* JSReceiver::GetIdentityHash(Isolate* isolate) {
DisallowHeapAllocation no_gc;
Object* maybe_hash = proxy->hash();
if (maybe_hash->IsSmi()) return Smi::cast(maybe_hash);
Smi* hash = Smi::FromInt(isolate->GenerateIdentityHash(Smi::kMaxValue));
proxy->set_hash(hash);
return hash;
}
Object* JSObject::GetIdentityHash(Isolate* isolate) {
DisallowHeapAllocation no_gc;
if (IsJSGlobalProxy()) {
return JSGlobalProxy::cast(this)->hash();
}
int hash = GetIdentityHashHelper(isolate, this);
if (hash == PropertyArray::kNoHashSentinel) {
@ -6524,11 +6510,8 @@ Object* JSObject::GetIdentityHash(Isolate* isolate) {
return Smi::FromInt(hash);
}
Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate) {
Smi* JSReceiver::GetOrCreateIdentityHash(Isolate* isolate) {
DisallowHeapAllocation no_gc;
if (IsJSGlobalProxy()) {
return GetOrCreateIdentityHashHelper(isolate, JSGlobalProxy::cast(this));
}
Object* hash_obj = GetIdentityHash(isolate);
if (!hash_obj->IsUndefined(isolate)) {
@ -6542,13 +6525,6 @@ Smi* JSObject::GetOrCreateIdentityHash(Isolate* isolate) {
return Smi::FromInt(hash);
}
Object* JSProxy::GetIdentityHash() { return hash(); }
Smi* JSProxy::GetOrCreateIdentityHash(Isolate* isolate) {
return GetOrCreateIdentityHashHelper(isolate, this);
}
Maybe<bool> JSObject::DeletePropertyWithInterceptor(LookupIterator* it,
ShouldThrow should_throw) {
Isolate* isolate = it->isolate();

View File

@ -2191,11 +2191,11 @@ class JSReceiver: public HeapObject {
// Retrieves a permanent object identity hash code. The undefined value might
// be returned in case no hash was created yet.
inline Object* GetIdentityHash(Isolate* isolate);
Object* GetIdentityHash(Isolate* isolate);
// Retrieves a permanent object identity hash code. May create and store a
// hash code if needed and none exists.
inline Smi* GetOrCreateIdentityHash(Isolate* isolate);
Smi* GetOrCreateIdentityHash(Isolate* isolate);
// Stores the hash code. The hash passed in must be masked with
// JSReceiver::kHashMask.
@ -2724,10 +2724,6 @@ class JSObject: public JSReceiver {
ElementsKind kind,
Object* object);
Object* GetIdentityHash(Isolate* isolate);
Smi* GetOrCreateIdentityHash(Isolate* isolate);
// Helper for fast versions of preventExtensions, seal, and freeze.
// attrs is one of NONE, SEALED, or FROZEN (depending on the operation).
template <PropertyAttributes attrs>
@ -4148,9 +4144,6 @@ class JSGlobalProxy : public JSObject {
// It is null value if this object is not used by any context.
DECL_ACCESSORS(native_context, Object)
// [hash]: The hash code property (undefined if not initialized yet).
DECL_ACCESSORS(hash, Object)
DECL_CAST(JSGlobalProxy)
inline bool IsDetachedFrom(JSGlobalObject* global) const;
@ -4163,8 +4156,7 @@ class JSGlobalProxy : public JSObject {
// Layout description.
static const int kNativeContextOffset = JSObject::kHeaderSize;
static const int kHashOffset = kNativeContextOffset + kPointerSize;
static const int kSize = kHashOffset + kPointerSize;
static const int kSize = kNativeContextOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalProxy);
@ -4903,8 +4895,6 @@ class JSProxy: public JSReceiver {
DECL_ACCESSORS(handler, Object)
// [target]: The target property.
DECL_ACCESSORS(target, JSReceiver)
// [hash]: The hash code property (undefined if not initialized yet).
DECL_ACCESSORS(hash, Object)
static MaybeHandle<Context> GetFunctionRealm(Handle<JSProxy> proxy);
@ -4993,8 +4983,7 @@ class JSProxy: public JSReceiver {
// Layout description.
static const int kTargetOffset = JSReceiver::kHeaderSize;
static const int kHandlerOffset = kTargetOffset + kPointerSize;
static const int kHashOffset = kHandlerOffset + kPointerSize;
static const int kSize = kHashOffset + kPointerSize;
static const int kSize = kHandlerOffset + kPointerSize;
// kTargetOffset aliases with the elements of JSObject. The fact that
// JSProxy::target is a Javascript value which cannot be confused with an
@ -5007,10 +4996,6 @@ class JSProxy: public JSReceiver {
// No weak fields.
typedef BodyDescriptor BodyDescriptorWeak;
Object* GetIdentityHash();
Smi* GetOrCreateIdentityHash(Isolate* isolate);
static Maybe<bool> SetPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Symbol> private_name,
PropertyDescriptor* desc,