Reviewers: rossberg,

Description:
Fix JavaScript accessors on objects with interceptors.

This fixes how Object.defineProperty() defines JavaScript accessors on
objects with installed API interceptors. The definition itself does not
cause any interceptors to be called, whereas any subsequent accesses on
said object will still fire the interceptor. This behavior is in sync
with API accessors.

[email protected]
BUG=v8:1651,chromium:94666
TEST=cctest/test-api


Please review this at http://codereview.chromium.org/9021019/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files:
  M src/objects.cc
  M test/cctest/test-api.cc


Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index e1931887b864f6e1e8cf0ea722218df8e45cbcee..ae5aa78cae57fc078a87ed41d290a3c9b10a1597 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -4352,7 +4352,7 @@ MaybeObject* JSObject::DefineGetterSetter(String* name,
   } else {
     // Lookup the name.
     LookupResult result(heap->isolate());
-    LocalLookup(name, &result);
+    LocalLookupRealNamedProperty(name, &result);
     if (result.IsProperty()) {
// TODO(mstarzinger): We should check for result.IsDontDelete() here once
       // we only call into the runtime once to set both getter and setter.
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 8b618d4906125d77c88361235bedac41405f0226..d19ef61f17da3ebb1d2c736236a073ba073d0e07 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -1459,6 +1459,54 @@ THREADED_TEST(SwitchFromAccessorToInterceptor) {
   ExpectInt32("child.interceptor_age", 9999);
 }

+THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
+  v8::HandleScope scope;
+  Handle<FunctionTemplate> child = FunctionTemplate::New();
+  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
+  LocalContext env;
+  env->Global()->Set(v8_str("Child"), child->GetFunction());
+  CompileRun("var child = new Child;"
+             "function setter(i) { this.accessor_age = i; };"
+             "function getter() { return this.accessor_age; };"
+             "function setAge(i) { child.age = i; };"
+ "Object.defineProperty(child, 'age', { get:getter, set:setter });"
+             "for(var i = 0; i <= 10000; i++) setAge(i);");
+  // All i < 10000 go to the interceptor.
+  ExpectInt32("child.interceptor_age", 9999);
+  // The last i goes to the JavaScript accessor.
+  ExpectInt32("child.accessor_age", 10000);
+  // The installed JavaScript getter is still intact.
+ // This last part is a regression test for issue 1651 and relies on the fact + // that both interceptor and accessor are being installed on the same object.
+  ExpectInt32("child.age", 10000);
+  ExpectBoolean("child.hasOwnProperty('age')", true);
+  ExpectUndefined("Object.getOwnPropertyDescriptor(child, 'age').value");
+}
+
+THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
+  v8::HandleScope scope;
+  Handle<FunctionTemplate> child = FunctionTemplate::New();
+  AddInterceptor(child, InterceptorGetter, InterceptorSetter);
+  LocalContext env;
+  env->Global()->Set(v8_str("Child"), child->GetFunction());
+  CompileRun("var child = new Child;"
+             "function setter(i) { this.accessor_age = i; };"
+             "function getter() { return this.accessor_age; };"
+             "function setAge(i) { child.age = i; };"
+ "Object.defineProperty(child, 'age', { get:getter, set:setter });"
+             "for(var i = 20000; i >= 9999; i--) setAge(i);");
+  // All i >= 10000 go to the accessor.
+  ExpectInt32("child.accessor_age", 10000);
+  // The last i goes to the interceptor.
+  ExpectInt32("child.interceptor_age", 9999);
+  // The installed JavaScript getter is still intact.
+ // This last part is a regression test for issue 1651 and relies on the fact + // that both interceptor and accessor are being installed on the same object.
+  ExpectInt32("child.age", 10000);
+  ExpectBoolean("child.hasOwnProperty('age')", true);
+  ExpectUndefined("Object.getOwnPropertyDescriptor(child, 'age').value");
+}
+
 THREADED_TEST(SwitchFromInterceptorToProperty) {
   v8::HandleScope scope;
   Handle<FunctionTemplate> parent = FunctionTemplate::New();


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

Reply via email to