Previously, the hash was stored on the underlying global object, since
it was stored in the hidden property table. This patch moves to an
implementation modeled on JSProxy, adding a new 'hash' field to JSGlobalProxy.
This allows storing the global proxy in a Map, Set, WeakMap, or WeakSet and
accessing it even after the proxy has been attached to a new global, which
is Firefox's current behavior and was the consensus of a recent thread on public-script-coord:
http://lists.w3.org/Archives/Public/public-script-coord/2014AprJun/0012.html
R=verwaest@chromium.org
Review URL: https://codereview.chromium.org/
254433002
git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@21150
ce2b1a6d-e550-0410-aec6-
3dcde31c8c00
// Set global_proxy.__proto__ to js_global after ConfigureGlobalObjects
// Return the global proxy.
+ Handle<JSGlobalProxy> global_proxy;
if (global_object.location() != NULL) {
ASSERT(global_object->IsJSGlobalProxy());
- Handle<JSGlobalProxy> global_proxy =
- Handle<JSGlobalProxy>::cast(global_object);
+ global_proxy = Handle<JSGlobalProxy>::cast(global_object);
factory()->ReinitializeJSGlobalProxy(global_proxy, global_proxy_function);
- return global_proxy;
} else {
- return Handle<JSGlobalProxy>::cast(
+ global_proxy = Handle<JSGlobalProxy>::cast(
factory()->NewJSObject(global_proxy_function, TENURED));
+ global_proxy->set_hash(heap()->undefined_value());
}
+ return global_proxy;
}
ASSERT(constructor->has_initial_map());
Handle<Map> map(constructor->initial_map(), isolate());
+ // The proxy's hash should be retained across reinitialization.
+ Handle<Object> hash(object->hash(), isolate());
+
// Check that the already allocated object has the same size and type as
// objects allocated using the constructor.
ASSERT(map->instance_size() == object->map()->instance_size());
Heap* heap = isolate()->heap();
// Reinitialize the object from the constructor map.
heap->InitializeJSObjectFromMap(*object, *properties, *map);
+
+ // Restore the saved hash.
+ object->set_hash(*hash);
}
ACCESSORS(GlobalObject, global_receiver, JSObject, kGlobalReceiverOffset)
ACCESSORS(JSGlobalProxy, native_context, Object, kNativeContextOffset)
+ACCESSORS(JSGlobalProxy, hash, Object, kHashOffset)
ACCESSORS(AccessorInfo, name, Object, kNameOffset)
ACCESSORS_TO_SMI(AccessorInfo, flag, kFlagOffset)
}
-Smi* JSReceiver::GenerateIdentityHash() {
- Isolate* isolate = GetIsolate();
-
+static Smi* GenerateIdentityHash(Isolate* isolate) {
int hash_value;
int attempts = 0;
do {
void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
+ ASSERT(!object->IsJSGlobalProxy());
Isolate* isolate = object->GetIsolate();
SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
}
+template<typename ProxyType>
+static Handle<Object> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
+ Isolate* isolate = proxy->GetIsolate();
+
+ Handle<Object> hash(proxy->hash(), isolate);
+ if (hash->IsSmi()) return hash;
+
+ hash = handle(GenerateIdentityHash(isolate), isolate);
+ proxy->set_hash(*hash);
+ return hash;
+}
+
+
Object* JSObject::GetIdentityHash() {
DisallowHeapAllocation no_gc;
Isolate* isolate = GetIsolate();
+ if (IsJSGlobalProxy()) {
+ return JSGlobalProxy::cast(this)->hash();
+ }
Object* stored_value =
GetHiddenProperty(isolate->factory()->identity_hash_string());
return stored_value->IsSmi()
Handle<Object> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
- Handle<Object> hash(object->GetIdentityHash(), object->GetIsolate());
- if (hash->IsSmi())
- return hash;
+ if (object->IsJSGlobalProxy()) {
+ return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
+ }
Isolate* isolate = object->GetIsolate();
- hash = handle(object->GenerateIdentityHash(), isolate);
- Handle<Object> result = SetHiddenProperty(object,
- isolate->factory()->identity_hash_string(), hash);
-
- if (result->IsUndefined()) {
- // Trying to get hash of detached proxy.
- return handle(Smi::FromInt(0), isolate);
- }
+ Handle<Object> hash(object->GetIdentityHash(), isolate);
+ if (hash->IsSmi()) return hash;
+ hash = handle(GenerateIdentityHash(isolate), isolate);
+ SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
return hash;
}
Handle<Object> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
- Isolate* isolate = proxy->GetIsolate();
-
- Handle<Object> hash(proxy->GetIdentityHash(), isolate);
- if (hash->IsSmi())
- return hash;
-
- hash = handle(proxy->GenerateIdentityHash(), isolate);
- proxy->set_hash(*hash);
- return hash;
+ return GetOrCreateIdentityHashHelper(proxy);
}
DisallowHeapAllocation no_gc;
ASSERT(key->IsUniqueName());
if (IsJSGlobalProxy()) {
+ // JSGlobalProxies store their hash internally.
+ ASSERT(*key != GetHeap()->identity_hash_string());
// For a proxy, use the prototype as target object.
Object* proxy_parent = GetPrototype();
// If the proxy is detached, return undefined.
ASSERT(key->IsUniqueName());
if (object->IsJSGlobalProxy()) {
+ // JSGlobalProxies store their hash internally.
+ ASSERT(*key != *isolate->factory()->identity_hash_string());
// For a proxy, use the prototype as target object.
Handle<Object> proxy_parent(object->GetPrototype(), isolate);
// If the proxy is detached, return undefined.
KeyCollectionType type);
protected:
- Smi* GenerateIdentityHash();
-
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithDefinedSetter(
Handle<JSReceiver> object,
Handle<JSReceiver> setter,
// 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)
+
// Casting.
static inline JSGlobalProxy* cast(Object* obj);
// Layout description.
static const int kNativeContextOffset = JSObject::kHeaderSize;
- static const int kSize = kNativeContextOffset + kPointerSize;
+ static const int kHashOffset = kNativeContextOffset + kPointerSize;
+ static const int kSize = kHashOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSGlobalProxy);
}
+THREADED_TEST(GlobalProxyIdentityHash) {
+ LocalContext env;
+ v8::Isolate* isolate = env->GetIsolate();
+ v8::HandleScope scope(isolate);
+ Handle<Object> global_proxy = env->Global();
+ int hash1 = global_proxy->GetIdentityHash();
+ // Hash should be retained after being detached.
+ env->DetachGlobal();
+ int hash2 = global_proxy->GetIdentityHash();
+ CHECK_EQ(hash1, hash2);
+ {
+ // Re-attach global proxy to a new context, hash should stay the same.
+ LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
+ int hash3 = global_proxy->GetIdentityHash();
+ CHECK_EQ(hash1, hash3);
+ }
+}
+
+
THREADED_TEST(SymbolProperties) {
i::FLAG_harmony_symbols = true;