Revision: 9396
Author:   [email protected]
Date:     Thu Sep 22 06:54:53 2011
Log:      Implement identity hashes for proxies.

[email protected]
BUG=v8:1543,v8:1565
TEST=

Review URL: http://codereview.chromium.org/7754015
http://code.google.com/p/v8/source/detail?r=9396

Added:
 /branches/bleeding_edge/test/mjsunit/harmony/proxies-hash.js
Modified:
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/handles.cc
 /branches/bleeding_edge/src/handles.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/objects-debug.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects-printer.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/test/mjsunit/harmony/proxies.js

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/harmony/proxies-hash.js Thu Sep 22 06:54:53 2011
@@ -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)
=======================================
--- /branches/bleeding_edge/src/api.cc  Wed Sep 21 06:28:09 2011
+++ /branches/bleeding_edge/src/api.cc  Thu Sep 22 06:54:53 2011
@@ -3209,7 +3209,7 @@
   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 @@
   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 @@
   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;
   }
=======================================
--- /branches/bleeding_edge/src/handles.cc      Tue Sep 13 05:53:28 2011
+++ /branches/bleeding_edge/src/handles.cc      Thu Sep 22 06:54:53 2011
@@ -421,17 +421,16 @@
 }


-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<ObjectHashTable> PutIntoObjectHashTable(Handle<ObjectHashTable> table,
-                                               Handle<JSObject> key,
+                                               Handle<JSReceiver> key,
                                                Handle<Object> value) {
   CALL_HEAP_FUNCTION(table->GetIsolate(),
                      table->Put(*key, *value),
=======================================
--- /branches/bleeding_edge/src/handles.h       Tue Sep 13 05:53:28 2011
+++ /branches/bleeding_edge/src/handles.h       Thu Sep 22 06:54:53 2011
@@ -267,10 +267,9 @@
// 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);
-
-int GetIdentityHash(Handle<JSObject> obj);
+Handle<Object> GetHiddenProperties(Handle<JSObject> obj, CreationFlag flag);
+
+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> 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
=======================================
--- /branches/bleeding_edge/src/heap.cc Thu Sep 22 05:57:54 2011
+++ /branches/bleeding_edge/src/heap.cc Thu Sep 22 06:54:53 2011
@@ -3565,6 +3565,7 @@
   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 @@
   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::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 @@

   // 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());
   }

@@ -3786,6 +3791,13 @@
     CreateFillerObjectAt(
         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;
 }
=======================================
--- /branches/bleeding_edge/src/heap.h  Thu Sep 22 04:30:04 2011
+++ /branches/bleeding_edge/src/heap.h  Thu Sep 22 06:54:53 2011
@@ -495,6 +495,7 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc        Thu Sep 22 04:30:04 2011
+++ /branches/bleeding_edge/src/objects-debug.cc        Thu Sep 22 06:54:53 2011
@@ -546,13 +546,14 @@


 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());
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Thu Sep 22 04:30:04 2011
+++ /branches/bleeding_edge/src/objects-inl.h   Thu Sep 22 06:54:53 2011
@@ -3834,6 +3834,7 @@


 ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
+ACCESSORS(JSProxy, hash, Object, kHashOffset)
 ACCESSORS(JSFunctionProxy, call_trap, Object, kCallTrapOffset)
 ACCESSORS(JSFunctionProxy, construct_trap, Object, kConstructTrapOffset)

@@ -4307,6 +4308,13 @@
   }
   return this;
 }
+
+
+MaybeObject* JSReceiver::GetIdentityHash(CreationFlag flag) {
+  return IsJSProxy()
+      ? JSProxy::cast(this)->GetIdentityHash(flag)
+      : JSObject::cast(this)->GetIdentityHash(flag);
+}


 bool JSObject::HasHiddenPropertiesObject() {
@@ -4461,27 +4469,27 @@
 }


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

=======================================
--- /branches/bleeding_edge/src/objects-printer.cc      Thu Sep 22 04:30:04 2011
+++ /branches/bleeding_edge/src/objects-printer.cc      Thu Sep 22 06:54:53 2011
@@ -671,6 +671,8 @@
   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");
 }

=======================================
--- /branches/bleeding_edge/src/objects.cc      Thu Sep 22 05:57:54 2011
+++ /branches/bleeding_edge/src/objects.cc      Thu Sep 22 06:54:53 2011
@@ -3139,7 +3139,7 @@
 }


-MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) {
+MaybeObject* JSObject::GetHiddenProperties(CreationFlag flag) {
   Isolate* isolate = GetIsolate();
   Heap* heap = isolate->heap();
   Object* holder = BypassGlobalProxy();
@@ -3179,8 +3179,36 @@
 }


-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);
     if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj;
@@ -3203,17 +3231,7 @@
     }
   }

-  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,
@@ -3222,6 +3240,16 @@
   }
   return hash;
 }
+
+
+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,
@@ -11542,9 +11570,9 @@
 }


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


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


-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();
=======================================
--- /branches/bleeding_edge/src/objects.h       Thu Sep 22 04:30:04 2011
+++ /branches/bleeding_edge/src/objects.h       Thu Sep 22 06:54:53 2011
@@ -282,6 +282,13 @@
 };


+// 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 @@
   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 @@
   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);
-
-  // 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* GetHiddenProperties(CreationFlag 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 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 @@

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

// 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 @@
   // [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 @@
       JSReceiver* receiver,
       uint32_t index);

+  MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
+
   // Turn this into an (empty) JSObject.
   void Fix();

@@ -6751,7 +6763,8 @@
   // 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 @@
   STATIC_CHECK(kPaddingSize >= 0);

   typedef FixedBodyDescriptor<kHandlerOffset,
-                              kHandlerOffset + kPointerSize,
+                              kPaddingOffset,
                               kSize> BodyDescriptor;

  private:
@@ -6790,7 +6803,7 @@
 #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;
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Thu Sep 22 04:30:04 2011
+++ /branches/bleeding_edge/src/runtime.cc      Thu Sep 22 06:54:53 2011
@@ -714,9 +714,7 @@
   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 @@
   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);
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/proxies.js Thu Sep 22 03:45:37 2011 +++ /branches/bleeding_edge/test/mjsunit/harmony/proxies.js Thu Sep 22 06:54:53 2011
@@ -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 @@
 // 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 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 @@
   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)

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to