Revision: 22236
Author:   [email protected]
Date:     Mon Jul  7 11:00:44 2014 UTC
Log:      Treat ExecutableAccessorInfo as regular data properties.

BUG=
[email protected], [email protected]

Review URL: https://codereview.chromium.org/368783006
http://code.google.com/p/v8/source/detail?r=22236

Modified:
 /branches/bleeding_edge/src/accessors.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/test/cctest/test-api.cc
 /branches/bleeding_edge/test/mjsunit/es7/object-observe.js

=======================================
--- /branches/bleeding_edge/src/accessors.cc    Wed Jul  2 07:01:31 2014 UTC
+++ /branches/bleeding_edge/src/accessors.cc    Mon Jul  7 11:00:44 2014 UTC
@@ -191,16 +191,7 @@
   Handle<JSObject> object = Handle<JSObject>::cast(
       Utils::OpenHandle(*info.This()));
   Handle<Object> value = Utils::OpenHandle(*val);
-  // This means one of the object's prototypes is a JSArray and the
-  // object does not have a 'length' property.  Calling SetProperty
-  // causes an infinite loop.
-  if (!object->IsJSArray()) {
-    MaybeHandle<Object> maybe_result =
-        JSObject::SetOwnPropertyIgnoreAttributes(
-            object, isolate->factory()->length_string(), value, NONE);
-    maybe_result.Check();
-    return;
-  }
+  ASSERT(object->IsJSArray());

   value = FlattenNumber(isolate, value);

@@ -871,13 +862,7 @@
     function = Handle<JSFunction>(function_raw, isolate);
   }

-  if (!function->should_have_prototype()) {
-    // Since we hit this accessor, object will have no prototype property.
-    MaybeHandle<Object> maybe_result =
-        JSObject::SetOwnPropertyIgnoreAttributes(
-            receiver, isolate->factory()->prototype_string(), value, NONE);
-    return maybe_result.ToHandleChecked();
-  }
+  ASSERT(function->should_have_prototype());

   Handle<Object> old_value;
bool is_observed = *function == *receiver && function->map()->is_observed();
=======================================
--- /branches/bleeding_edge/src/ic.cc   Mon Jul  7 09:57:29 2014 UTC
+++ /branches/bleeding_edge/src/ic.cc   Mon Jul  7 11:00:44 2014 UTC
@@ -1206,7 +1206,9 @@

     if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
     if (lookup->holder() == *receiver) return lookup->CanHoldValue(value);
-    if (lookup->IsPropertyCallbacks()) return true;
+    if (lookup->IsPropertyCallbacks() &&
+        !lookup->GetCallbackObject()->IsExecutableAccessorInfo())
+      return true;
// JSGlobalProxy either stores on the global object in the prototype, or
     // goes into the runtime if access checks are needed, so this is always
     // safe.
=======================================
--- /branches/bleeding_edge/src/objects.cc      Mon Jul  7 09:57:29 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc      Mon Jul  7 11:00:44 2014 UTC
@@ -3096,6 +3096,25 @@
         *done = true;
         if (!result.IsReadOnly()) {
Handle<Object> callback_object(result.GetCallbackObject(), isolate); + // Only store via executable access info setters if the holder is the
+          // receiver or on its hidden prototype chain.
+          if (callback_object->IsExecutableAccessorInfo()) {
+            Handle<JSObject> current = object;
+            while (*current != result.holder()) {
+              // There is a callbacks holder, so we are guaranteed that all
+              // objects in between are JSObjects.
+              Handle<JSObject> prototype(
+                  JSObject::cast(current->GetPrototype()));
+              if (!current->IsJSGlobalProxy() &&
+                  !prototype->map()->is_hidden_prototype()) {
+                *done = false;
+                break;
+              }
+              current = prototype;
+            }
+ // Break out of the switch after breaking out of the loop above.
+            if (*current != result.holder()) break;
+          }
           return SetPropertyWithCallback(object, name, value,
                                          handle(result.holder()),
                                          callback_object, strict_mode);
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Mon Jul 7 07:19:46 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-api.cc Mon Jul 7 11:00:44 2014 UTC
@@ -1924,7 +1924,7 @@
                  Handle<String> name,
                  v8::AccessorGetterCallback getter,
                  v8::AccessorSetterCallback setter) {
-  templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
+  templ->InstanceTemplate()->SetAccessor(name, getter, setter);
 }

 void AddInterceptor(Handle<FunctionTemplate> templ,
@@ -1937,6 +1937,7 @@
 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
   v8::HandleScope scope(CcTest::isolate());
Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
+  parent->SetHiddenPrototype(true);
Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
   child->Inherit(parent);
   AddAccessor(parent, v8_str("age"),
@@ -1946,7 +1947,7 @@
   env->Global()->Set(v8_str("Child"), child->GetFunction());
   CompileRun("var child = new Child;"
              "child.age = 10;");
-  ExpectBoolean("child.hasOwnProperty('age')", false);
+  ExpectBoolean("child.hasOwnProperty('age')", true);
   ExpectInt32("child.age", 10);
   ExpectInt32("child.accessor_age", 10);
 }
@@ -9985,10 +9986,13 @@
   LocalContext context(NULL, global_template);

   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
-  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
-  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
-  Local<ObjectTemplate> proto = t->PrototypeTemplate();
+  t->SetHiddenPrototype(true);
+  Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
+  t->Inherit(pt);
+  Local<ObjectTemplate> proto = pt->PrototypeTemplate();
   Local<ObjectTemplate> instance = t->InstanceTemplate();
+  instance->SetNamedPropertyHandler(ShadowNamedGet);
+  instance->SetIndexedPropertyHandler(ShadowIndexedGet);

   proto->Set(v8_str("f"),
              v8::FunctionTemplate::New(isolate,
@@ -18535,12 +18539,12 @@
 TEST(SetterOnConstructorPrototype) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
-  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetAccessor(v8_str("x"),
-                     GetterWhichReturns42,
-                     SetterWhichSetsYOnThisTo23);
+  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate);
+  templ->SetHiddenPrototype(true);
+  templ->InstanceTemplate()->SetAccessor(v8_str("x"), GetterWhichReturns42,
+                                         SetterWhichSetsYOnThisTo23);
   LocalContext context;
-  context->Global()->Set(v8_str("P"), templ->NewInstance());
+ context->Global()->Set(v8_str("P"), templ->InstanceTemplate()->NewInstance());
   CompileRun("function C1() {"
              "  this.x = 23;"
              "};"
@@ -18562,8 +18566,7 @@
 script = v8_compile("new C2();");
   for (int i = 0; i < 10; i++) {
v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
-    CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
-    CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
+    CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
   }
 }

@@ -18649,11 +18652,11 @@
   }

   // Use an API object with accessors as prototype.
-  Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetAccessor(v8_str("x"),
-                     GetterWhichReturns42,
-                     SetterWhichSetsYOnThisTo23);
-  context->Global()->Set(v8_str("P"), templ->NewInstance());
+  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate);
+  templ->SetHiddenPrototype(true);
+  templ->InstanceTemplate()->SetAccessor(v8_str("x"), GetterWhichReturns42,
+                                         SetterWhichSetsYOnThisTo23);
+ context->Global()->Set(v8_str("P"), templ->InstanceTemplate()->NewInstance());

   // This compile will get the code from the compilation cache.
   CompileRun(source);
@@ -21067,16 +21070,16 @@
 }


-static void CheckInstanceCheckedResult(int getters,
-                                       int setters,
-                                       bool expects_callbacks,
+static void CheckInstanceCheckedResult(int getters, int setters,
+ bool expects_callbacks, bool is_setter,
                                        TryCatch* try_catch) {
   if (expects_callbacks) {
     CHECK(!try_catch->HasCaught());
     CHECK_EQ(getters, instance_checked_getter_count);
     CHECK_EQ(setters, instance_checked_setter_count);
   } else {
-    CHECK(try_catch->HasCaught());
+    CHECK((is_setter && !try_catch->HasCaught()) ||
+          (!is_setter && try_catch->HasCaught()));
     CHECK_EQ(0, instance_checked_getter_count);
     CHECK_EQ(0, instance_checked_setter_count);
   }
@@ -21091,33 +21094,38 @@

   // Test path through generic runtime code.
   CompileRun("obj.foo");
-  CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(1, 0, expects_callbacks, false, &try_catch);
   CompileRun("obj.foo = 23");
-  CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(1, 1, expects_callbacks, true, &try_catch);
+  if (!expects_callbacks) CompileRun("delete obj.foo");

   // Test path through generated LoadIC and StoredIC.
   CompileRun("function test_get(o) { o.foo; }"
              "test_get(obj);");
-  CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(2, 1, expects_callbacks, false, &try_catch);
   CompileRun("test_get(obj);");
-  CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(3, 1, expects_callbacks, false, &try_catch);
   CompileRun("test_get(obj);");
-  CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(4, 1, expects_callbacks, false, &try_catch);
   CompileRun("function test_set(o) { o.foo = 23; }"
              "test_set(obj);");
-  CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(4, 2, expects_callbacks, true, &try_catch);
+  if (!expects_callbacks) CompileRun("delete obj.foo");
   CompileRun("test_set(obj);");
-  CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(4, 3, expects_callbacks, true, &try_catch);
+  if (!expects_callbacks) CompileRun("delete obj.foo");
   CompileRun("test_set(obj);");
-  CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(4, 4, expects_callbacks, true, &try_catch);
+  if (!expects_callbacks) CompileRun("delete obj.foo");

   // Test path through optimized code.
   CompileRun("%OptimizeFunctionOnNextCall(test_get);"
              "test_get(obj);");
-  CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
+  CheckInstanceCheckedResult(5, 4, expects_callbacks, false, &try_catch);
   CompileRun("%OptimizeFunctionOnNextCall(test_set);"
              "test_set(obj);");
-  CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
+  if (!expects_callbacks) CompileRun("delete obj.foo");
+  CheckInstanceCheckedResult(5, 5, expects_callbacks, true, &try_catch);

   // Cleanup so that closures start out fresh in next check.
   CompileRun("%DeoptimizeFunction(test_get);"
@@ -21189,14 +21197,16 @@
   LocalContext context;
   v8::HandleScope scope(context->GetIsolate());

+  Local<FunctionTemplate> proto_templ =
+      FunctionTemplate::New(context->GetIsolate());
+  proto_templ->SetHiddenPrototype(true);
+  Local<ObjectTemplate> proto = proto_templ->InstanceTemplate();
+  proto->SetAccessor(
+      v8_str("foo"), InstanceCheckedGetter, InstanceCheckedSetter,
+      Handle<Value>(), v8::DEFAULT, v8::None,
+      v8::AccessorSignature::New(context->GetIsolate(), proto_templ));
Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
-  Local<ObjectTemplate> proto = templ->PrototypeTemplate();
-  proto->SetAccessor(v8_str("foo"),
-                     InstanceCheckedGetter, InstanceCheckedSetter,
-                     Handle<Value>(),
-                     v8::DEFAULT,
-                     v8::None,
- v8::AccessorSignature::New(context->GetIsolate(), templ));
+  templ->Inherit(proto_templ);
   context->Global()->Set(v8_str("f"), templ->GetFunction());

   printf("Testing positive ...\n");
=======================================
--- /branches/bleeding_edge/test/mjsunit/es7/object-observe.js Wed Jul 2 16:59:04 2014 UTC +++ /branches/bleeding_edge/test/mjsunit/es7/object-observe.js Mon Jul 7 11:00:44 2014 UTC
@@ -1685,7 +1685,9 @@
 Object.observe(obj, observer.callback);
 obj.prototype = 7;
 Object.deliverChangeRecords(observer.callback);
-observer.assertNotCalled();
+observer.assertCallbackRecords([
+    { object: obj, name: 'prototype', type: 'add'},
+]);


// Check that changes in observation status are detected in all IC states and

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to