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
This commit is contained in:
rossberg@chromium.org 2011-09-22 13:54:53 +00:00
parent fd71ed8d36
commit d938560d59
13 changed files with 209 additions and 84 deletions

View File

@ -3209,7 +3209,7 @@ bool v8::Object::SetHiddenValue(v8::Handle<v8::String> key,
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(
self,
i::JSObject::ALLOW_CREATION));
i::ALLOW_CREATION));
i::Handle<i::Object> key_obj = Utils::OpenHandle(*key);
i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
EXCEPTION_PREAMBLE(isolate);
@ -3233,7 +3233,7 @@ v8::Local<v8::Value> v8::Object::GetHiddenValue(v8::Handle<v8::String> key) {
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(
self,
i::JSObject::OMIT_CREATION));
i::OMIT_CREATION));
if (hidden_props->IsUndefined()) {
return v8::Local<v8::Value>();
}
@ -3257,7 +3257,7 @@ bool v8::Object::DeleteHiddenValue(v8::Handle<v8::String> key) {
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> hidden_props(i::GetHiddenProperties(
self,
i::JSObject::OMIT_CREATION));
i::OMIT_CREATION));
if (hidden_props->IsUndefined()) {
return true;
}

View File

@ -421,17 +421,16 @@ Handle<Object> PreventExtensions(Handle<JSObject> object) {
}
Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
JSObject::HiddenPropertiesFlag flag) {
Handle<Object> GetHiddenProperties(Handle<JSObject> obj, CreationFlag flag) {
CALL_HEAP_FUNCTION(obj->GetIsolate(),
obj->GetHiddenProperties(flag),
Object);
}
int GetIdentityHash(Handle<JSObject> obj) {
int GetIdentityHash(Handle<JSReceiver> 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<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
Handle<JSObject> key,
Handle<JSReceiver> key,
Handle<Object> value) {
CALL_HEAP_FUNCTION(table->GetIsolate(),
table->Put(*key, *value),

View File

@ -267,10 +267,9 @@ Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value);
// properties and HiddenPropertiesFlag::ALLOW_CREATION is passed, then a new
// hidden property object will be allocated. Otherwise Heap::undefined_value
// is returned.
Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
JSObject::HiddenPropertiesFlag flag);
Handle<Object> GetHiddenProperties(Handle<JSObject> obj, CreationFlag flag);
int GetIdentityHash(Handle<JSObject> obj);
int GetIdentityHash(Handle<JSReceiver> obj);
Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
Handle<Object> DeleteProperty(Handle<JSObject> obj, Handle<String> prop);
@ -348,7 +347,7 @@ Handle<Object> SetPrototype(Handle<JSFunction> function,
Handle<Object> PreventExtensions(Handle<JSObject> object);
Handle<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
Handle<JSObject> key,
Handle<JSReceiver> key,
Handle<Object> value);
// Does lazy compilation of the given function. Returns true on success and

View File

@ -3565,6 +3565,7 @@ MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
if (!maybe_result->To<JSProxy>(&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<JSFunctionProxy>(&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>(&map)) return maybe_map_obj;
MaybeObject* maybe = AllocateMap(type, size);
if (!maybe->To<Map>(&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("<freezing call trap>");
if (!maybe_name->To<String>(&name)) return maybe_name;
maybe = LookupAsciiSymbol("<freezing call trap>");
if (!maybe->To<String>(&name)) return maybe;
SharedFunctionInfo* shared;
MaybeObject* maybe_shared = AllocateSharedFunctionInfo(name);
if (!maybe_shared->To<SharedFunctionInfo>(&shared)) return maybe_shared;
maybe = AllocateSharedFunctionInfo(name);
if (!maybe->To<SharedFunctionInfo>(&shared)) return maybe;
JSFunction* func;
MaybeObject* maybe_func =
InitializeFunction(JSFunction::cast(object), shared, the_hole_value());
if (!maybe_func->To<JSFunction>(&func)) return maybe_func;
maybe = InitializeFunction(
JSFunction::cast(object), shared, the_hole_value());
if (!maybe->To<JSFunction>(&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<Object>(&hash) && hash->IsSmi()) {
maybe = jsobj->SetIdentityHash(hash, ALLOW_CREATION);
if (maybe->IsFailure()) return maybe;
}
return object;
}

View File

@ -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);

View File

@ -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());

View File

@ -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;
}

View File

@ -671,6 +671,8 @@ void JSProxy::JSProxyPrint(FILE* out) {
PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
PrintF(out, " - handler = ");
handler()->Print(out);
PrintF(out, " - hash = ");
hash()->Print(out);
PrintF(out, "\n");
}

View File

@ -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<JSObject>(&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();

View File

@ -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<NumberDictionaryShape, uint32_t> {
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<ObjectHashTableShape, JSObject*> {
class ObjectHashTable: public HashTable<ObjectHashTableShape, JSReceiver*> {
public:
static inline ObjectHashTable* cast(Object* obj) {
ASSERT(obj->IsHashTable());
@ -2945,16 +2952,16 @@ class ObjectHashTable: public HashTable<ObjectHashTableShape, JSObject*> {
// 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<kHandlerOffset,
kHandlerOffset + kPointerSize,
kPaddingOffset,
kSize> 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;

View File

@ -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<Object> value(args[2]);
Handle<ObjectHashTable> table(weakmap->table());
Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);

View File

@ -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)

View File

@ -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)