From d938560d5987b60c7aa79b77aa6a0190feb269bb Mon Sep 17 00:00:00 2001 From: "rossberg@chromium.org" Date: Thu, 22 Sep 2011 13:54:53 +0000 Subject: [PATCH] Implement identity hashes for proxies. R=mstarzinger@chromium.org BUG=v8:1543,v8:1565 TEST= Review URL: http://codereview.chromium.org/7754015 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9396 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/api.cc | 6 +-- src/handles.cc | 9 ++-- src/handles.h | 7 ++- src/heap.cc | 36 ++++++++++----- src/heap.h | 1 + src/objects-debug.cc | 5 ++- src/objects-inl.h | 24 ++++++---- src/objects-printer.cc | 2 + src/objects.cc | 64 +++++++++++++++++++-------- src/objects.h | 55 ++++++++++++++--------- src/runtime.cc | 7 +-- test/mjsunit/harmony/proxies-hash.js | 66 ++++++++++++++++++++++++++++ test/mjsunit/harmony/proxies.js | 11 +++-- 13 files changed, 209 insertions(+), 84 deletions(-) create mode 100644 test/mjsunit/harmony/proxies-hash.js diff --git a/src/api.cc b/src/api.cc index a0f330f8b7..6479ad015d 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3209,7 +3209,7 @@ bool v8::Object::SetHiddenValue(v8::Handle key, i::Handle self = Utils::OpenHandle(this); i::Handle hidden_props(i::GetHiddenProperties( self, - i::JSObject::ALLOW_CREATION)); + i::ALLOW_CREATION)); i::Handle key_obj = Utils::OpenHandle(*key); i::Handle value_obj = Utils::OpenHandle(*value); EXCEPTION_PREAMBLE(isolate); @@ -3233,7 +3233,7 @@ v8::Local v8::Object::GetHiddenValue(v8::Handle key) { i::Handle self = Utils::OpenHandle(this); i::Handle hidden_props(i::GetHiddenProperties( self, - i::JSObject::OMIT_CREATION)); + i::OMIT_CREATION)); if (hidden_props->IsUndefined()) { return v8::Local(); } @@ -3257,7 +3257,7 @@ bool v8::Object::DeleteHiddenValue(v8::Handle key) { i::Handle self = Utils::OpenHandle(this); i::Handle hidden_props(i::GetHiddenProperties( self, - i::JSObject::OMIT_CREATION)); + i::OMIT_CREATION)); if (hidden_props->IsUndefined()) { return true; } diff --git a/src/handles.cc b/src/handles.cc index 35c363c10c..b37d164676 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -421,17 +421,16 @@ Handle PreventExtensions(Handle object) { } -Handle GetHiddenProperties(Handle obj, - JSObject::HiddenPropertiesFlag flag) { +Handle GetHiddenProperties(Handle obj, CreationFlag flag) { CALL_HEAP_FUNCTION(obj->GetIsolate(), obj->GetHiddenProperties(flag), Object); } -int GetIdentityHash(Handle obj) { +int GetIdentityHash(Handle obj) { CALL_AND_RETRY(obj->GetIsolate(), - obj->GetIdentityHash(JSObject::ALLOW_CREATION), + obj->GetIdentityHash(ALLOW_CREATION), return Smi::cast(__object__)->value(), return 0); } @@ -886,7 +885,7 @@ Handle GetEnumPropertyKeys(Handle object, Handle PutIntoObjectHashTable(Handle table, - Handle key, + Handle key, Handle value) { CALL_HEAP_FUNCTION(table->GetIsolate(), table->Put(*key, *value), diff --git a/src/handles.h b/src/handles.h index 7eaf4de927..3f4e2293a4 100644 --- a/src/handles.h +++ b/src/handles.h @@ -267,10 +267,9 @@ Handle SetPrototype(Handle obj, Handle value); // properties and HiddenPropertiesFlag::ALLOW_CREATION is passed, then a new // hidden property object will be allocated. Otherwise Heap::undefined_value // is returned. -Handle GetHiddenProperties(Handle obj, - JSObject::HiddenPropertiesFlag flag); +Handle GetHiddenProperties(Handle obj, CreationFlag flag); -int GetIdentityHash(Handle obj); +int GetIdentityHash(Handle obj); Handle DeleteElement(Handle obj, uint32_t index); Handle DeleteProperty(Handle obj, Handle prop); @@ -348,7 +347,7 @@ Handle SetPrototype(Handle function, Handle PreventExtensions(Handle object); Handle PutIntoObjectHashTable(Handle table, - Handle key, + Handle key, Handle value); // Does lazy compilation of the given function. Returns true on success and diff --git a/src/heap.cc b/src/heap.cc index f2f9985ff6..4bd31a8a45 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -3565,6 +3565,7 @@ MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) { if (!maybe_result->To(&result)) return maybe_result; result->InitializeBody(map->instance_size(), Smi::FromInt(0)); result->set_handler(handler); + result->set_hash(undefined_value()); return result; } @@ -3588,6 +3589,7 @@ MaybeObject* Heap::AllocateJSFunctionProxy(Object* handler, if (!maybe_result->To(&result)) return maybe_result; result->InitializeBody(map->instance_size(), Smi::FromInt(0)); result->set_handler(handler); + result->set_hash(undefined_value()); result->set_call_trap(call_trap); result->set_construct_trap(construct_trap); return result; @@ -3737,13 +3739,16 @@ MaybeObject* Heap::CopyJSObject(JSObject* source) { MaybeObject* Heap::ReinitializeJSReceiver( JSReceiver* object, InstanceType type, int size) { - ASSERT(type >= FIRST_JS_RECEIVER_TYPE); + ASSERT(type >= FIRST_JS_OBJECT_TYPE); + + // Save identity hash. + MaybeObject* maybe_hash = object->GetIdentityHash(OMIT_CREATION); // Allocate fresh map. // TODO(rossberg): Once we optimize proxies, cache these maps. Map* map; - MaybeObject* maybe_map_obj = AllocateMap(type, size); - if (!maybe_map_obj->To(&map)) return maybe_map_obj; + MaybeObject* maybe = AllocateMap(type, size); + if (!maybe->To(&map)) return maybe; // Check that the receiver has at least the size of the fresh object. int size_difference = object->map()->instance_size() - map->instance_size(); @@ -3760,24 +3765,24 @@ MaybeObject* Heap::ReinitializeJSReceiver( // Reset the map for the object. object->set_map(map); + JSObject* jsobj = JSObject::cast(object); // Reinitialize the object from the constructor map. - InitializeJSObjectFromMap(JSObject::cast(object), - FixedArray::cast(properties), map); + InitializeJSObjectFromMap(jsobj, FixedArray::cast(properties), map); // Functions require some minimal initialization. if (type == JS_FUNCTION_TYPE) { map->set_function_with_prototype(true); String* name; - MaybeObject* maybe_name = LookupAsciiSymbol(""); - if (!maybe_name->To(&name)) return maybe_name; + maybe = LookupAsciiSymbol(""); + if (!maybe->To(&name)) return maybe; SharedFunctionInfo* shared; - MaybeObject* maybe_shared = AllocateSharedFunctionInfo(name); - if (!maybe_shared->To(&shared)) return maybe_shared; + maybe = AllocateSharedFunctionInfo(name); + if (!maybe->To(&shared)) return maybe; JSFunction* func; - MaybeObject* maybe_func = - InitializeFunction(JSFunction::cast(object), shared, the_hole_value()); - if (!maybe_func->To(&func)) return maybe_func; + maybe = InitializeFunction( + JSFunction::cast(object), shared, the_hole_value()); + if (!maybe->To(&func)) return maybe; func->set_context(isolate()->context()->global_context()); } @@ -3787,6 +3792,13 @@ MaybeObject* Heap::ReinitializeJSReceiver( object->address() + map->instance_size(), size_difference); } + // Inherit identity, if it was present. + Object* hash; + if (maybe_hash->To(&hash) && hash->IsSmi()) { + maybe = jsobj->SetIdentityHash(hash, ALLOW_CREATION); + if (maybe->IsFailure()) return maybe; + } + return object; } diff --git a/src/heap.h b/src/heap.h index 7f05b4e295..db258e7826 100644 --- a/src/heap.h +++ b/src/heap.h @@ -495,6 +495,7 @@ class Heap { // size, but keeping the original prototype. The receiver must have at least // the size of the new object. The object is reinitialized and behaves as an // object that has been freshly allocated. + // Returns failure if an error occured, otherwise object. MUST_USE_RESULT MaybeObject* ReinitializeJSReceiver(JSReceiver* object, InstanceType type, int size); diff --git a/src/objects-debug.cc b/src/objects-debug.cc index f62c828d90..6fea3c6712 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -546,13 +546,14 @@ void JSRegExp::JSRegExpVerify() { void JSProxy::JSProxyVerify() { - ASSERT(IsJSProxy()); + CHECK(IsJSProxy()); VerifyPointer(handler()); + ASSERT(hash()->IsSmi() || hash()->IsUndefined()); } void JSFunctionProxy::JSFunctionProxyVerify() { - ASSERT(IsJSFunctionProxy()); + CHECK(IsJSFunctionProxy()); JSProxyVerify(); VerifyPointer(call_trap()); VerifyPointer(construct_trap()); diff --git a/src/objects-inl.h b/src/objects-inl.h index 3b3f6259d6..f476599f5f 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -3834,6 +3834,7 @@ void JSBuiltinsObject::set_javascript_builtin_code(Builtins::JavaScript id, ACCESSORS(JSProxy, handler, Object, kHandlerOffset) +ACCESSORS(JSProxy, hash, Object, kHashOffset) ACCESSORS(JSFunctionProxy, call_trap, Object, kCallTrapOffset) ACCESSORS(JSFunctionProxy, construct_trap, Object, kConstructTrapOffset) @@ -4309,6 +4310,13 @@ Object* JSObject::BypassGlobalProxy() { } +MaybeObject* JSReceiver::GetIdentityHash(CreationFlag flag) { + return IsJSProxy() + ? JSProxy::cast(this)->GetIdentityHash(flag) + : JSObject::cast(this)->GetIdentityHash(flag); +} + + bool JSObject::HasHiddenPropertiesObject() { ASSERT(!IsJSGlobalProxy()); return GetPropertyAttributePostInterceptor(this, @@ -4461,27 +4469,27 @@ MaybeObject* StringDictionaryShape::AsObject(String* key) { } -bool ObjectHashTableShape::IsMatch(JSObject* key, Object* other) { - return key == JSObject::cast(other); +bool ObjectHashTableShape::IsMatch(JSReceiver* key, Object* other) { + return key == JSReceiver::cast(other); } -uint32_t ObjectHashTableShape::Hash(JSObject* key) { - MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION); +uint32_t ObjectHashTableShape::Hash(JSReceiver* key) { + MaybeObject* maybe_hash = key->GetIdentityHash(OMIT_CREATION); ASSERT(!maybe_hash->IsFailure()); return Smi::cast(maybe_hash->ToObjectUnchecked())->value(); } -uint32_t ObjectHashTableShape::HashForObject(JSObject* key, Object* other) { - MaybeObject* maybe_hash = JSObject::cast(other)->GetIdentityHash( - JSObject::OMIT_CREATION); +uint32_t ObjectHashTableShape::HashForObject(JSReceiver* key, Object* other) { + MaybeObject* maybe_hash = + JSReceiver::cast(other)->GetIdentityHash(OMIT_CREATION); ASSERT(!maybe_hash->IsFailure()); return Smi::cast(maybe_hash->ToObjectUnchecked())->value(); } -MaybeObject* ObjectHashTableShape::AsObject(JSObject* key) { +MaybeObject* ObjectHashTableShape::AsObject(JSReceiver* key) { return key; } diff --git a/src/objects-printer.cc b/src/objects-printer.cc index bb8039276a..072bd656d5 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -671,6 +671,8 @@ void JSProxy::JSProxyPrint(FILE* out) { PrintF(out, " - map = 0x%p\n", reinterpret_cast(map())); PrintF(out, " - handler = "); handler()->Print(out); + PrintF(out, " - hash = "); + hash()->Print(out); PrintF(out, "\n"); } diff --git a/src/objects.cc b/src/objects.cc index ce0259b16c..dd7a38fe97 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -3139,7 +3139,7 @@ MaybeObject* JSObject::NormalizeElements() { } -MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) { +MaybeObject* JSObject::GetHiddenProperties(CreationFlag flag) { Isolate* isolate = GetIsolate(); Heap* heap = isolate->heap(); Object* holder = BypassGlobalProxy(); @@ -3179,7 +3179,35 @@ MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) { } -MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) { +Smi* JSReceiver::GenerateIdentityHash() { + Isolate* isolate = GetIsolate(); + + int hash_value; + int attempts = 0; + do { + // Generate a random 32-bit hash value but limit range to fit + // within a smi. + hash_value = V8::Random(isolate) & Smi::kMaxValue; + attempts++; + } while (hash_value == 0 && attempts < 30); + hash_value = hash_value != 0 ? hash_value : 1; // never return 0 + + return Smi::FromInt(hash_value); +} + + +MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) { + JSObject* hidden_props; + MaybeObject* maybe = GetHiddenProperties(flag); + if (!maybe->To(&hidden_props)) return maybe; + maybe = hidden_props->SetLocalPropertyIgnoreAttributes( + GetHeap()->identity_hash_symbol(), hash, NONE); + if (maybe->IsFailure()) return maybe; + return this; +} + + +MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) { Isolate* isolate = GetIsolate(); Object* hidden_props_obj; { MaybeObject* maybe_obj = GetHiddenProperties(flag); @@ -3203,17 +3231,7 @@ MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) { } } - int hash_value; - int attempts = 0; - do { - // Generate a random 32-bit hash value but limit range to fit - // within a smi. - hash_value = V8::Random(isolate) & Smi::kMaxValue; - attempts++; - } while (hash_value == 0 && attempts < 30); - hash_value = hash_value != 0 ? hash_value : 1; // never return 0 - - Smi* hash = Smi::FromInt(hash_value); + Smi* hash = GenerateIdentityHash(); { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes( hash_symbol, hash, @@ -3224,6 +3242,16 @@ MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) { } +MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) { + Object* hash = this->hash(); + if (!hash->IsSmi() && flag == ALLOW_CREATION) { + hash = GenerateIdentityHash(); + set_hash(hash); + } + return hash; +} + + MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) { // Check local property, ignore interceptor. @@ -11542,9 +11570,9 @@ MaybeObject* StringDictionary::TransformPropertiesToFastFor( } -Object* ObjectHashTable::Lookup(JSObject* key) { +Object* ObjectHashTable::Lookup(JSReceiver* key) { // If the object does not have an identity hash, it was never used as a key. - MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION); + MaybeObject* maybe_hash = key->GetIdentityHash(OMIT_CREATION); if (maybe_hash->IsFailure()) return GetHeap()->undefined_value(); int entry = FindEntry(key); if (entry == kNotFound) return GetHeap()->undefined_value(); @@ -11552,10 +11580,10 @@ Object* ObjectHashTable::Lookup(JSObject* key) { } -MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) { +MaybeObject* ObjectHashTable::Put(JSReceiver* key, Object* value) { // Make sure the key object has an identity hash code. int hash; - { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION); + { MaybeObject* maybe_hash = key->GetIdentityHash(ALLOW_CREATION); if (maybe_hash->IsFailure()) return maybe_hash; hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); } @@ -11585,7 +11613,7 @@ MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) { } -void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) { +void ObjectHashTable::AddEntry(int entry, JSReceiver* key, Object* value) { set(EntryToIndex(entry), key); set(EntryToIndex(entry) + 1, value); ElementAdded(); diff --git a/src/objects.h b/src/objects.h index 97112451f8..ed58f64f6f 100644 --- a/src/objects.h +++ b/src/objects.h @@ -282,6 +282,13 @@ enum NormalizedMapSharingMode { }; +// Indicates whether a get method should implicitly create the object looked up. +enum CreationFlag { + ALLOW_CREATION, + OMIT_CREATION +}; + + // Instance size sentinel for objects of variable size. static const int kVariableSizeSentinel = 0; @@ -1386,11 +1393,18 @@ class JSReceiver: public HeapObject { MUST_USE_RESULT MaybeObject* SetPrototype(Object* value, bool skip_hidden_prototypes); + // Retrieves a permanent object identity hash code. The undefined value might + // be returned in case no has been created yet and OMIT_CREATION was used. + inline MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag); + // Lookup a property. If found, the result is valid and has // detailed information. void LocalLookup(String* name, LookupResult* result); void Lookup(String* name, LookupResult* result); + protected: + Smi* GenerateIdentityHash(); + private: PropertyAttributes GetPropertyAttribute(JSReceiver* receiver, LookupResult* result, @@ -1596,22 +1610,15 @@ class JSObject: public JSReceiver { MUST_USE_RESULT inline MaybeObject* SetHiddenPropertiesObject( Object* hidden_obj); - // Indicates whether the hidden properties object should be created. - enum HiddenPropertiesFlag { ALLOW_CREATION, OMIT_CREATION }; - // Retrieves the hidden properties object. // // The undefined value might be returned in case no hidden properties object // is present and creation was omitted. inline bool HasHiddenProperties(); - MUST_USE_RESULT MaybeObject* GetHiddenProperties(HiddenPropertiesFlag flag); + MUST_USE_RESULT MaybeObject* GetHiddenProperties(CreationFlag flag); - // Retrieves a permanent object identity hash code. - // - // The identity hash is stored as a hidden property. The undefined value might - // be returned in case no hidden properties object is present and creation was - // omitted. - MUST_USE_RESULT MaybeObject* GetIdentityHash(HiddenPropertiesFlag flag); + MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag); + MUST_USE_RESULT MaybeObject* SetIdentityHash(Object* hash, CreationFlag flag); MUST_USE_RESULT MaybeObject* DeleteProperty(String* name, DeleteMode mode); MUST_USE_RESULT MaybeObject* DeleteElement(uint32_t index, DeleteMode mode); @@ -2925,10 +2932,10 @@ class NumberDictionary: public Dictionary { class ObjectHashTableShape { public: - static inline bool IsMatch(JSObject* key, Object* other); - static inline uint32_t Hash(JSObject* key); - static inline uint32_t HashForObject(JSObject* key, Object* object); - MUST_USE_RESULT static inline MaybeObject* AsObject(JSObject* key); + static inline bool IsMatch(JSReceiver* key, Object* other); + static inline uint32_t Hash(JSReceiver* key); + static inline uint32_t HashForObject(JSReceiver* key, Object* object); + MUST_USE_RESULT static inline MaybeObject* AsObject(JSReceiver* key); static const int kPrefixSize = 0; static const int kEntrySize = 2; }; @@ -2936,7 +2943,7 @@ class ObjectHashTableShape { // ObjectHashTable maps keys that are JavaScript objects to object values by // using the identity hash of the key for hashing purposes. -class ObjectHashTable: public HashTable { +class ObjectHashTable: public HashTable { public: static inline ObjectHashTable* cast(Object* obj) { ASSERT(obj->IsHashTable()); @@ -2945,16 +2952,16 @@ class ObjectHashTable: public HashTable { // Looks up the value associated with the given key. The undefined value is // returned in case the key is not present. - Object* Lookup(JSObject* key); + Object* Lookup(JSReceiver* key); // Adds (or overwrites) the value associated with the given key. Mapping a // key to the undefined value causes removal of the whole entry. - MUST_USE_RESULT MaybeObject* Put(JSObject* key, Object* value); + MUST_USE_RESULT MaybeObject* Put(JSReceiver* key, Object* value); private: friend class MarkCompactCollector; - void AddEntry(int entry, JSObject* key, Object* value); + void AddEntry(int entry, JSReceiver* key, Object* value); void RemoveEntry(int entry, Heap* heap); inline void RemoveEntry(int entry); @@ -6677,6 +6684,9 @@ class JSProxy: public JSReceiver { // [handler]: The handler property. DECL_ACCESSORS(handler, Object) + // [hash]: The hash code property (undefined if not initialized yet). + DECL_ACCESSORS(hash, Object) + // Casting. static inline JSProxy* cast(Object* obj); @@ -6723,6 +6733,8 @@ class JSProxy: public JSReceiver { JSReceiver* receiver, uint32_t index); + MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag); + // Turn this into an (empty) JSObject. void Fix(); @@ -6751,7 +6763,8 @@ class JSProxy: public JSReceiver { // size as a virgin JSObject. This is essential for becoming a JSObject // upon freeze. static const int kHandlerOffset = HeapObject::kHeaderSize; - static const int kPaddingOffset = kHandlerOffset + kPointerSize; + static const int kHashOffset = kHandlerOffset + kPointerSize; + static const int kPaddingOffset = kHashOffset + kPointerSize; static const int kSize = JSObject::kHeaderSize; static const int kHeaderSize = kPaddingOffset; static const int kPaddingSize = kSize - kPaddingOffset; @@ -6759,7 +6772,7 @@ class JSProxy: public JSReceiver { STATIC_CHECK(kPaddingSize >= 0); typedef FixedBodyDescriptor BodyDescriptor; private: @@ -6790,7 +6803,7 @@ class JSFunctionProxy: public JSProxy { #endif // Layout description. - static const int kCallTrapOffset = kHandlerOffset + kPointerSize; + static const int kCallTrapOffset = JSProxy::kPaddingOffset; static const int kConstructTrapOffset = kCallTrapOffset + kPointerSize; static const int kPaddingOffset = kConstructTrapOffset + kPointerSize; static const int kSize = JSFunction::kSize; diff --git a/src/runtime.cc b/src/runtime.cc index cb6307250f..c569bdfdab 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -714,9 +714,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) { NoHandleAllocation ha; ASSERT(args.length() == 2); CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0); - // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys - // because they cannot be cast to JSObject to get an identity hash code. - CONVERT_ARG_CHECKED(JSObject, key, 1); + CONVERT_ARG_CHECKED(JSReceiver, key, 1); return weakmap->table()->Lookup(*key); } @@ -725,8 +723,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) { HandleScope scope(isolate); ASSERT(args.length() == 3); CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0); - // TODO(mstarzinger): See Runtime_WeakMapGet above. - CONVERT_ARG_CHECKED(JSObject, key, 1); + CONVERT_ARG_CHECKED(JSReceiver, key, 1); Handle value(args[2]); Handle table(weakmap->table()); Handle new_table = PutIntoObjectHashTable(table, key, value); diff --git a/test/mjsunit/harmony/proxies-hash.js b/test/mjsunit/harmony/proxies-hash.js new file mode 100644 index 0000000000..2bf1830134 --- /dev/null +++ b/test/mjsunit/harmony/proxies-hash.js @@ -0,0 +1,66 @@ +// Copyright 2011 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-proxies --harmony-weakmaps + + +// Helper. + +function TestWithProxies(test, handler) { + test(handler, Proxy.create) + test(handler, function(h) {return Proxy.createFunction(h, function() {})}) +} + + +// Weak maps. + +function TestWeakMap(fix) { + TestWithProxies(TestWeakMap2, fix) +} + +function TestWeakMap2(fix, create) { + var handler = {fix: function() { return {} }} + var p1 = create(handler) + var p2 = create(handler) + var p3 = create(handler) + fix(p3) + + var m = new WeakMap + m.set(p1, 123); + m.set(p2, 321); + assertSame(123, m.get(p1)); + assertSame(321, m.get(p2)); + + fix(p1) + fix(p2) + assertSame(123, m.get(p1)); + assertSame(321, m.get(p2)); +} + +TestWeakMap(Object.seal) +TestWeakMap(Object.freeze) +TestWeakMap(Object.preventExtensions) diff --git a/test/mjsunit/harmony/proxies.js b/test/mjsunit/harmony/proxies.js index 9963b659f5..e20d4c2fcc 100644 --- a/test/mjsunit/harmony/proxies.js +++ b/test/mjsunit/harmony/proxies.js @@ -1,4 +1,4 @@ -// Copyright 2008 the V8 project authors. All rights reserved. +// Copyright 2011 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -1665,7 +1665,6 @@ TestKeysThrow([], { // Fixing (Object.freeze, Object.seal, Object.preventExtensions, // Object.isFrozen, Object.isSealed, Object.isExtensible) -// TODO(rossberg): use TestWithProxies to include function proxies function TestFix(names, handler) { var proto = {p: 77} var assertFixing = function(o, s, f, e) { @@ -2020,8 +2019,8 @@ function CreateFrozen(handler, callTrap, constructTrap) { function TestCall(isStrict, callTrap) { assertEquals(42, callTrap(5, 37)) -// TODO(rossberg): unrelated bug: this does not succeed for optimized code. -// assertEquals(isStrict ? undefined : global_object, receiver) + // TODO(rossberg): unrelated bug: this does not succeed for optimized code. + // assertEquals(isStrict ? undefined : global_object, receiver) var f = Proxy.createFunction({}, callTrap) receiver = 333 @@ -2048,8 +2047,8 @@ function TestCall(isStrict, callTrap) { var f = CreateFrozen({}, callTrap) receiver = 333 assertEquals(42, f(11, 31)) -// TODO(rossberg): unrelated bug: this does not succeed for optimized code. -// assertEquals(isStrict ? undefined : global, receiver) + // TODO(rossberg): unrelated bug: this does not succeed for optimized code. + // assertEquals(isStrict ? undefined : global, receiver) receiver = 333 assertEquals(42, Function.prototype.call.call(f, o, 20, 22)) assertEquals(o, receiver)