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:
parent
fd71ed8d36
commit
d938560d59
@ -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;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
36
src/heap.cc
36
src/heap.cc
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
66
test/mjsunit/harmony/proxies-hash.js
Normal file
66
test/mjsunit/harmony/proxies-hash.js
Normal 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)
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user