Fix for issue 339:
authoriposva@chromium.org <iposva@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 12 May 2009 22:07:10 +0000 (22:07 +0000)
committeriposva@chromium.org <iposva@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 12 May 2009 22:07:10 +0000 (22:07 +0000)
- Move GetHiddenProperties functionality from object.cc to handle.cc to
  be more robust in the presence of GC in the middle of the function.

Review URL: http://codereview.chromium.org/115267

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1924 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/handles.cc
src/handles.h
src/objects.cc
src/objects.h
test/cctest/test-api.cc

index 773483d609f37a48a91cce0d5bb1bab4c5196ef1..2d9efe60e84eec6a47825c2437665163c8842dfd 100644 (file)
@@ -273,7 +273,35 @@ Handle<Object> GetPrototype(Handle<Object> obj) {
 
 Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
                                    bool create_if_needed) {
-  CALL_HEAP_FUNCTION(obj->GetHiddenProperties(create_if_needed), Object);
+  Handle<String> key = Factory::hidden_symbol();
+
+  if (obj->HasFastProperties()) {
+    // If the object has fast properties, check whether the first slot
+    // in the descriptor array matches the hidden symbol. Since the
+    // hidden symbols hash code is zero (and no other string has hash
+    // code zero) it will always occupy the first entry if present.
+    DescriptorArray* descriptors = obj->map()->instance_descriptors();
+    DescriptorReader r(descriptors);
+    if (!r.eos() && (r.GetKey() == *key) && r.IsProperty()) {
+      ASSERT(r.type() == FIELD);
+      return Handle<Object>(obj->FastPropertyAt(r.GetFieldIndex()));
+    }
+  }
+
+  // Only attempt to find the hidden properties in the local object and not
+  // in the prototype chain.  Note that HasLocalProperty() can cause a GC in
+  // the general case in the presence of interceptors.
+  if (!obj->HasLocalProperty(*key)) {
+    // Hidden properties object not found. Allocate a new hidden properties
+    // object if requested. Otherwise return the undefined value.
+    if (create_if_needed) {
+      Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function());
+      return SetProperty(obj, key, hidden_obj, DONT_ENUM);
+    } else {
+      return Factory::undefined_value();
+    }
+  }
+  return GetProperty(obj, key);
 }
 
 
index 652d6c70e5f67ea991e10e1d5304d456277428d2..cf5ed56058901160c66c140d2dc37c4fbbe49cc8 100644 (file)
@@ -228,6 +228,9 @@ Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver,
 
 Handle<Object> GetPrototype(Handle<Object> obj);
 
+// Return the object's hidden properties object. If the object has no hidden
+// properties and create_if_needed is true, then a new hidden property object
+// will be allocated. Otherwise the Heap::undefined_value is returned.
 Handle<Object> GetHiddenProperties(Handle<JSObject> obj, bool create_if_needed);
 
 Handle<Object> DeleteElement(Handle<JSObject> obj, uint32_t index);
index 28a397e5ee4c0e5baf3cbd3c240f412970fbb9d5..0a8ee836635e7fb58e9c6a9e7ae879e576ce5124 100644 (file)
@@ -5145,42 +5145,6 @@ bool JSObject::HasLocalElement(uint32_t index) {
 }
 
 
-Object* JSObject::GetHiddenProperties(bool create_if_needed) {
-  String* key = Heap::hidden_symbol();
-  if (this->HasFastProperties()) {
-    // If the object has fast properties, check whether the first slot
-    // in the descriptor array matches the hidden symbol. Since the
-    // hidden symbols hash code is zero (and no other string has hash
-    // code zero) it will always occupy the first entry if present.
-    DescriptorArray* descriptors = this->map()->instance_descriptors();
-    DescriptorReader r(descriptors);
-    if (!r.eos() && (r.GetKey() == key) && r.IsProperty()) {
-      ASSERT(r.type() == FIELD);
-      return FastPropertyAt(r.GetFieldIndex());
-    }
-  }
-
-  // Only attempt to find the hidden properties in the local object and not
-  // in the prototype chain.  Note that HasLocalProperty() can cause a GC in
-  // the general case, but in this case we know it won't hit an interceptor.
-  if (!this->HasLocalProperty(key)) {
-    // Hidden properties object not found. Allocate a new hidden properties
-    // object if requested. Otherwise return the undefined value.
-    if (create_if_needed) {
-      Object* obj = Heap::AllocateJSObject(
-          Top::context()->global_context()->object_function());
-      if (obj->IsFailure()) {
-        return obj;
-      }
-      return this->SetProperty(key, obj, DONT_ENUM);
-    } else {
-      return Heap::undefined_value();
-    }
-  }
-  return this->GetProperty(key);
-}
-
-
 bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
   // Check access rights if needed.
   if (IsAccessCheckNeeded() &&
index 3e132ff19eaf46007ccf43888b972909b5dfb38a..2619c891bd5c5cf7f64769b5a65a9ad90afb2d88 100644 (file)
@@ -1286,11 +1286,6 @@ class JSObject: public HeapObject {
   // Return the object's prototype (might be Heap::null_value()).
   inline Object* GetPrototype();
 
-  // Return the object's hidden properties object. If the object has no hidden
-  // properties and create_if_needed is true, then a new hidden property object
-  // will be allocated. Otherwise the Heap::undefined_value is returned.
-  Object* GetHiddenProperties(bool create_if_needed);
-
   // Tells whether the index'th element is present.
   inline bool HasElement(uint32_t index);
   bool HasElementWithReceiver(JSObject* receiver, uint32_t index);
index 4b55b6be073cf3dd44d672a51c661a8844a7cfa7..7c834c7a410e6120b00f36db97f76664c3de4d6f 100644 (file)
@@ -1327,6 +1327,38 @@ THREADED_TEST(HiddenProperties) {
 }
 
 
+static v8::Handle<Value> InterceptorForHiddenProperties(
+    Local<String> name, const AccessorInfo& info) {
+  // Make sure objects move.
+  bool saved_always_compact = i::FLAG_always_compact;
+  if (!i::FLAG_never_compact) {
+    i::FLAG_always_compact = true;
+  }
+  // The whole goal of this interceptor is to cause a GC during local property
+  // lookup.
+  i::Heap::CollectAllGarbage();
+  i::FLAG_always_compact = saved_always_compact;
+  return v8::Handle<Value>();
+}
+
+
+THREADED_TEST(HiddenPropertiesWithInterceptors) {
+  v8::HandleScope scope;
+  LocalContext context;
+
+  v8::Local<v8::String> key = v8_str("api-test::hidden-key");
+
+  // Associate an interceptor with an object and start setting hidden values.
+  Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+  Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
+  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
+  Local<v8::Function> function = fun_templ->GetFunction();
+  Local<v8::Object> obj = function->NewInstance();
+  CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
+  CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
+}
+
+
 THREADED_TEST(External) {
   v8::HandleScope scope;
   int x = 3;