Revision: 12230
Author:   [email protected]
Date:     Mon Jul 30 06:09:09 2012
Log: Limit initial size of hidden properties and store identity hashes inline.

BUG=v8:2211
TEST=test-heap/Regress2211

Review URL: https://chromiumcodereview.appspot.com/10827040
http://code.google.com/p/v8/source/detail?r=12230

Modified:
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/factory.cc
 /branches/bleeding_edge/src/factory.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/test/cctest/test-dictionary.cc
 /branches/bleeding_edge/test/cctest/test-heap-profiler.cc
 /branches/bleeding_edge/test/cctest/test-heap.cc

=======================================
--- /branches/bleeding_edge/src/api.cc  Mon Jul 23 07:22:46 2012
+++ /branches/bleeding_edge/src/api.cc  Mon Jul 30 06:09:09 2012
@@ -3303,9 +3303,10 @@
   i::HandleScope scope(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
+  i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
   i::Handle<i::Object> value_obj = Utils::OpenHandle(*value);
   i::Handle<i::Object> result =
-      i::JSObject::SetHiddenProperty(self, key_obj, value_obj);
+      i::JSObject::SetHiddenProperty(self, key_symbol, value_obj);
   return *result == *self;
 }

@@ -3317,7 +3318,8 @@
   ENTER_V8(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
-  i::Handle<i::Object> result(self->GetHiddenProperty(*key_obj));
+  i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
+  i::Handle<i::Object> result(self->GetHiddenProperty(*key_symbol));
   if (result->IsUndefined()) return v8::Local<v8::Value>();
   return Utils::ToLocal(result);
 }
@@ -3330,7 +3332,8 @@
   i::HandleScope scope(isolate);
   i::Handle<i::JSObject> self = Utils::OpenHandle(this);
   i::Handle<i::String> key_obj = Utils::OpenHandle(*key);
-  self->DeleteHiddenProperty(*key_obj);
+  i::Handle<i::String> key_symbol = FACTORY->LookupSymbol(key_obj);
+  self->DeleteHiddenProperty(*key_symbol);
   return true;
 }

=======================================
--- /branches/bleeding_edge/src/factory.cc      Wed Jul 25 04:12:29 2012
+++ /branches/bleeding_edge/src/factory.cc      Mon Jul 30 06:09:09 2012
@@ -1011,7 +1011,7 @@
 }


-void Factory::SetIdentityHash(Handle<JSObject> object, Object* hash) {
+void Factory::SetIdentityHash(Handle<JSObject> object, Smi* hash) {
   CALL_HEAP_FUNCTION_VOID(
       isolate(),
       object->SetIdentityHash(hash, ALLOW_CREATION));
=======================================
--- /branches/bleeding_edge/src/factory.h       Wed Jul 25 04:12:29 2012
+++ /branches/bleeding_edge/src/factory.h       Mon Jul 30 06:09:09 2012
@@ -297,7 +297,7 @@
   void BecomeJSObject(Handle<JSReceiver> object);
   void BecomeJSFunction(Handle<JSReceiver> object);

-  void SetIdentityHash(Handle<JSObject> object, Object* hash);
+  void SetIdentityHash(Handle<JSObject> object, Smi* hash);

   Handle<JSFunction> NewFunction(Handle<String> name,
                                  Handle<Object> prototype);
=======================================
--- /branches/bleeding_edge/src/objects.cc      Fri Jul 27 10:03:12 2012
+++ /branches/bleeding_edge/src/objects.cc      Mon Jul 30 06:09:09 2012
@@ -2761,7 +2761,7 @@
   Object* hash;
   if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
     Handle<JSObject> new_self(JSObject::cast(*self));
-    isolate->factory()->SetIdentityHash(new_self, hash);
+    isolate->factory()->SetIdentityHash(new_self, Smi::cast(hash));
   }
 }

@@ -3505,7 +3505,7 @@
 }


-MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
+MaybeObject* JSObject::SetIdentityHash(Smi* hash, CreationFlag flag) {
   MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
                                          hash);
   if (maybe->IsFailure()) return maybe;
@@ -3551,6 +3551,7 @@


 Object* JSObject::GetHiddenProperty(String* key) {
+  ASSERT(key->IsSymbol());
   if (IsJSGlobalProxy()) {
     // For a proxy, use the prototype as target object.
     Object* proxy_parent = GetPrototype();
@@ -3560,22 +3561,32 @@
     return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
   }
   ASSERT(!IsJSGlobalProxy());
-  MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
+  MaybeObject* hidden_lookup =
+      GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
-  if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
-    return GetHeap()->undefined_value();
-  }
-  StringDictionary* dictionary =
-      StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
-  int entry = dictionary->FindEntry(key);
- if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
-  return dictionary->ValueAt(entry);
+  Object* inline_value = hidden_lookup->ToObjectUnchecked();
+
+  if (inline_value->IsSmi()) {
+    // Handle inline-stored identity hash.
+    if (key == GetHeap()->identity_hash_symbol()) {
+      return inline_value;
+    } else {
+      return GetHeap()->undefined_value();
+    }
+  }
+
+  if (inline_value->IsUndefined()) return GetHeap()->undefined_value();
+
+  ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
+  Object* entry = hashtable->Lookup(key);
+  if (entry->IsTheHole()) return GetHeap()->undefined_value();
+  return entry;
 }


 Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
-                                 Handle<String> key,
-                                 Handle<Object> value) {
+                                           Handle<String> key,
+                                           Handle<Object> value) {
   CALL_HEAP_FUNCTION(obj->GetIsolate(),
                      obj->SetHiddenProperty(*key, *value),
                      Object);
@@ -3583,6 +3594,7 @@


 MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
+  ASSERT(key->IsSymbol());
   if (IsJSGlobalProxy()) {
     // For a proxy, use the prototype as target object.
     Object* proxy_parent = GetPrototype();
@@ -3592,27 +3604,31 @@
     return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
   }
   ASSERT(!IsJSGlobalProxy());
-  MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
-  StringDictionary* dictionary;
- if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
-
-  // If it was found, check if the key is already in the dictionary.
-  int entry = dictionary->FindEntry(key);
-  if (entry != StringDictionary::kNotFound) {
-    // If key was found, just update the value.
-    dictionary->ValueAtPut(entry, value);
-    return this;
-  }
-  // Key was not already in the dictionary, so add the entry.
-  MaybeObject* insert_result = dictionary->Add(key,
-                                               value,
- PropertyDetails(NONE, NORMAL));
-  StringDictionary* new_dict;
- if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
-  if (new_dict != dictionary) {
+
+  // If there is no backing store yet, store the identity hash inline.
+  MaybeObject* hidden_lookup =
+      GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
+  ASSERT(!hidden_lookup->IsFailure());
+  Object* inline_value = hidden_lookup->ToObjectUnchecked();
+
+  if (value->IsSmi() &&
+      key == GetHeap()->identity_hash_symbol() &&
+      (inline_value->IsUndefined() || inline_value->IsSmi())) {
+    return SetHiddenPropertiesHashTable(value);
+  }
+
+  hidden_lookup = GetHiddenPropertiesHashTable(CREATE_NEW_IF_ABSENT);
+  ObjectHashTable* hashtable;
+  if (!hidden_lookup->To(&hashtable)) return hidden_lookup;
+
+  // If it was found, check if the key is already in the dictionary.
+  MaybeObject* insert_result = hashtable->Put(key, value);
+  ObjectHashTable* new_table;
+  if (!insert_result->To(&new_table)) return insert_result;
+  if (new_table != hashtable) {
     // If adding the key expanded the dictionary (i.e., Add returned a new
     // dictionary), store it back to the object.
-    MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
+    MaybeObject* store_result = SetHiddenPropertiesHashTable(new_table);
     if (store_result->IsFailure()) return store_result;
   }
   // Return this to mark success.
@@ -3621,6 +3637,7 @@


 void JSObject::DeleteHiddenProperty(String* key) {
+  ASSERT(key->IsSymbol());
   if (IsJSGlobalProxy()) {
     // For a proxy, use the prototype as target object.
     Object* proxy_parent = GetPrototype();
@@ -3630,18 +3647,18 @@
     JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
     return;
   }
-  MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
+  MaybeObject* hidden_lookup =
+      GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
   if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
-  StringDictionary* dictionary =
-      StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
-  int entry = dictionary->FindEntry(key);
-  if (entry == StringDictionary::kNotFound) {
-    // Key wasn't in dictionary. Deletion is a success.
-    return;
-  }
-  // Key was in the dictionary. Remove it.
-  dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
+  // We never delete (inline-stored) identity hashes.
+  ASSERT(!hidden_lookup->ToObjectUnchecked()->IsSmi());
+
+  ObjectHashTable* hashtable =
+      ObjectHashTable::cast(hidden_lookup->ToObjectUnchecked());
+ MaybeObject* delete_result = hashtable->Put(key, GetHeap()->the_hole_value());
+  USE(delete_result);
+  ASSERT(!delete_result->IsFailure());  // Delete does not cause GC.
 }


@@ -3652,8 +3669,10 @@
 }


-MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
+MaybeObject* JSObject::GetHiddenPropertiesHashTable(
+    InitializeHiddenProperties init_option) {
   ASSERT(!IsJSGlobalProxy());
+  Object* inline_value;
   if (HasFastProperties()) {
     // If the object has fast properties, check whether the first slot
     // in the descriptor array matches the hidden symbol. Since the
@@ -3663,43 +3682,60 @@
     if ((descriptors->number_of_descriptors() > 0) &&
         (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
       ASSERT(descriptors->GetType(0) == FIELD);
-      Object* hidden_store =
-          this->FastPropertyAt(descriptors->GetFieldIndex(0));
-      return StringDictionary::cast(hidden_store);
+      inline_value = this->FastPropertyAt(descriptors->GetFieldIndex(0));
+    } else {
+      inline_value = GetHeap()->undefined_value();
     }
   } else {
     PropertyAttributes attributes;
// You can't install a getter on a property indexed by the hidden symbol, // so we can be sure that GetLocalPropertyPostInterceptor returns a real
     // object.
-    Object* lookup =
+    inline_value =
         GetLocalPropertyPostInterceptor(this,
                                         GetHeap()->hidden_symbol(),
                                         &attributes)->ToObjectUnchecked();
-    if (!lookup->IsUndefined()) {
-      return StringDictionary::cast(lookup);
-    }
-  }
-  if (!create_if_absent) return GetHeap()->undefined_value();
-  const int kInitialSize = 5;
-  MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
-  StringDictionary* dictionary;
-  if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
+  }
+
+  if (init_option == ONLY_RETURN_INLINE_VALUE ||
+      inline_value->IsHashTable()) {
+    return inline_value;
+  }
+
+  ObjectHashTable* hashtable;
+  static const int kInitialCapacity = 4;
+  MaybeObject* maybe_obj =
+      ObjectHashTable::Allocate(kInitialCapacity,
+ ObjectHashTable::USE_CUSTOM_MINIMUM_CAPACITY);
+  if (!maybe_obj->To<ObjectHashTable>(&hashtable)) return maybe_obj;
+
+  if (inline_value->IsSmi()) {
+    // We were storing the identity hash inline and now allocated an actual
+    // dictionary.  Put the identity hash into the new dictionary.
+    MaybeObject* insert_result =
+        hashtable->Put(GetHeap()->identity_hash_symbol(), inline_value);
+    ObjectHashTable* new_table;
+    if (!insert_result->To(&new_table)) return insert_result;
+    // We expect no resizing for the first insert.
+    ASSERT_EQ(hashtable, new_table);
+  }
+
   MaybeObject* store_result =
       SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
-                                 dictionary,
+                                 hashtable,
                                  DONT_ENUM,
                                  kNonStrictMode,
                                  OMIT_EXTENSIBILITY_CHECK);
   if (store_result->IsFailure()) return store_result;
-  return dictionary;
+  return hashtable;
 }


-MaybeObject* JSObject::SetHiddenPropertiesDictionary(
-    StringDictionary* dictionary) {
+MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) {
   ASSERT(!IsJSGlobalProxy());
-  ASSERT(HasHiddenProperties());
+  // We can store the identity hash inline iff there is no backing store
+  // for hidden properties yet.
+  ASSERT(HasHiddenProperties() != value->IsSmi());
   if (HasFastProperties()) {
     // If the object has fast properties, check whether the first slot
     // in the descriptor array matches the hidden symbol. Since the
@@ -3709,13 +3745,13 @@
     if ((descriptors->number_of_descriptors() > 0) &&
         (descriptors->GetKey(0) == GetHeap()->hidden_symbol())) {
       ASSERT(descriptors->GetType(0) == FIELD);
-      this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
+      this->FastPropertyAtPut(descriptors->GetFieldIndex(0), value);
       return this;
     }
   }
   MaybeObject* store_result =
       SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
-                                 dictionary,
+                                 value,
                                  DONT_ENUM,
                                  kNonStrictMode,
                                  OMIT_EXTENSIBILITY_CHECK);
@@ -11046,8 +11082,12 @@

 template<typename Shape, typename Key>
 MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
+ MinimumCapacity capacity_option,
                                              PretenureFlag pretenure) {
-  int capacity = ComputeCapacity(at_least_space_for);
+  ASSERT(!capacity_option || IS_POWER_OF_TWO(at_least_space_for));
+  int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
+                     ? at_least_space_for
+                     : ComputeCapacity(at_least_space_for);
   if (capacity > HashTable::kMaxCapacity) {
     return Failure::OutOfMemoryException();
   }
@@ -11156,7 +11196,9 @@
(capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
   Object* obj;
   { MaybeObject* maybe_obj =
-        Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
+        Allocate(nof * 2,
+                 USE_DEFAULT_MINIMUM_CAPACITY,
+                 pretenure ? TENURED : NOT_TENURED);
     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
   }

@@ -11185,7 +11227,9 @@
       !GetHeap()->InNewSpace(this);
   Object* obj;
   { MaybeObject* maybe_obj =
-        Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
+        Allocate(at_least_room_for,
+                 USE_DEFAULT_MINIMUM_CAPACITY,
+                 pretenure ? TENURED : NOT_TENURED);
     if (!maybe_obj->ToObject(&obj)) return maybe_obj;
   }

=======================================
--- /branches/bleeding_edge/src/objects.h       Thu Jul 26 01:27:20 2012
+++ /branches/bleeding_edge/src/objects.h       Mon Jul 30 06:09:09 2012
@@ -1731,7 +1731,7 @@

   static int GetIdentityHash(Handle<JSObject> obj);
   MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
- MUST_USE_RESULT MaybeObject* SetIdentityHash(Object* hash, CreationFlag flag); + MUST_USE_RESULT MaybeObject* SetIdentityHash(Smi* hash, CreationFlag flag);

   static Handle<Object> DeleteProperty(Handle<JSObject> obj,
                                        Handle<String> name);
@@ -2235,16 +2235,22 @@
       Object* setter,
       PropertyAttributes attributes);

-  // Returns the hidden properties backing store object, currently
-  // a StringDictionary, stored on this object.
-  // If no hidden properties object has been put on this object,
-  // return undefined, unless create_if_absent is true, in which case
-  // a new dictionary is created, added to this object, and returned.
-  MUST_USE_RESULT MaybeObject* GetHiddenPropertiesDictionary(
-      bool create_if_absent);
-  // Updates the existing hidden properties dictionary.
-  MUST_USE_RESULT MaybeObject* SetHiddenPropertiesDictionary(
-      StringDictionary* dictionary);
+
+  enum InitializeHiddenProperties {
+    CREATE_NEW_IF_ABSENT,
+    ONLY_RETURN_INLINE_VALUE
+  };
+
+  // If create_if_absent is true, return the hash table backing store
+  // for hidden properties.  If there is no backing store, allocate one.
+  // If create_if_absent is false, return the hash table backing store
+  // or the inline stored identity hash, whatever is found.
+  MUST_USE_RESULT MaybeObject* GetHiddenPropertiesHashTable(
+      InitializeHiddenProperties init_option);
+  // Set the hidden property backing store to either a hash table or
+  // the inline-stored identity hash.
+  MUST_USE_RESULT MaybeObject* SetHiddenPropertiesHashTable(
+      Object* value);

   DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject);
 };
@@ -2747,6 +2753,11 @@
 template<typename Shape, typename Key>
 class HashTable: public FixedArray {
  public:
+  enum MinimumCapacity {
+    USE_DEFAULT_MINIMUM_CAPACITY,
+    USE_CUSTOM_MINIMUM_CAPACITY
+  };
+
   // Wrapper methods
   inline uint32_t Hash(Key key) {
     if (Shape::UsesSeed) {
@@ -2799,6 +2810,7 @@
   // Returns a new HashTable object. Might return Failure.
   MUST_USE_RESULT static MaybeObject* Allocate(
       int at_least_space_for,
+      MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY,
       PretenureFlag pretenure = NOT_TENURED);

   // Computes the required capacity for a table holding the given
=======================================
--- /branches/bleeding_edge/test/cctest/test-dictionary.cc Mon Jun 25 06:57:52 2012 +++ /branches/bleeding_edge/test/cctest/test-dictionary.cc Mon Jul 30 06:09:09 2012
@@ -105,6 +105,12 @@
   LocalContext context;
   Handle<ObjectHashSet> table = FACTORY->NewObjectHashSet(1);
   Handle<JSObject> key = FACTORY->NewJSArray(0);
+  v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key);
+
+  // Force allocation of hash table backing store for hidden properties.
+  key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1"));
+  key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2"));
+  key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3"));

   // Simulate a full heap so that generating an identity hash code
   // in subsequent calls will request GC.
@@ -128,6 +134,12 @@
   LocalContext context;
   Handle<ObjectHashTable> table = FACTORY->NewObjectHashTable(1);
   Handle<JSObject> key = FACTORY->NewJSArray(0);
+  v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key);
+
+  // Force allocation of hash table backing store for hidden properties.
+  key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1"));
+  key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2"));
+  key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3"));

   // Simulate a full heap so that generating an identity hash code
   // in subsequent calls will request GC.
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Thu Jul 5 09:23:14 2012 +++ /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Mon Jul 30 06:09:09 2012
@@ -1468,7 +1468,7 @@

   v8::Handle<v8::Value> cHandle = env->Global()->Get(v8::String::New("c"));
   CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
-  cHandle->ToObject()->GetIdentityHash();
+  cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));

   snapshot = v8::HeapProfiler::TakeSnapshot(
       v8_str("HiddenPropertiesFastCase2"));
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Mon Jul 30 06:07:29 2012 +++ /branches/bleeding_edge/test/cctest/test-heap.cc Mon Jul 30 06:09:09 2012
@@ -1985,3 +1985,39 @@
   g->shared()->PrintLn();
 }
 #endif  // OBJECT_PRINT
+
+
+TEST(Regress2211) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  v8::Handle<v8::String> value = v8_str("val string");
+  Smi* hash = Smi::FromInt(321);
+  Heap* heap = Isolate::Current()->heap();
+
+  for (int i = 0; i < 2; i++) {
+    // Store identity hash first and common hidden property second.
+    v8::Handle<v8::Object> obj = v8::Object::New();
+    Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
+    CHECK(internal_obj->HasFastProperties());
+
+ // In the first iteration, set hidden value first and identity hash second.
+    // In the second iteration, reverse the order.
+    if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
+    MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
+                                                           ALLOW_CREATION);
+    CHECK(!maybe_obj->IsFailure());
+    if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
+
+    // Check values.
+    CHECK_EQ(hash,
+ internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
+    CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
+
+    // Check size.
+ DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
+    ObjectHashTable* hashtable = ObjectHashTable::cast(
+        internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
+    CHECK_LE(hashtable->SizeFor(hashtable->length()), 52);
+  }
+}

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

Reply via email to