Revision: 16495
Author:   [email protected]
Date:     Tue Sep  3 08:55:52 2013 UTC
Log:      Fix interceptor handling in crankshaft.

[email protected]

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

Modified:
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/test/cctest/test-api.cc

=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Mon Sep  2 09:27:27 2013 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Tue Sep  3 08:55:52 2013 UTC
@@ -4001,6 +4001,11 @@
expr->literal_index());
   return ast_context()->ReturnInstruction(instr, expr->id());
 }
+
+
+static bool CanInlinePropertyAccess(Map* type) {
+  return !type->is_dictionary_map() && !type->has_named_interceptor();
+}


 static void LookupInPrototypes(Handle<Map> map,
@@ -4008,8 +4013,8 @@
                                LookupResult* lookup) {
   while (map->prototype()->IsJSObject()) {
     Handle<JSObject> holder(JSObject::cast(map->prototype()));
-    if (!holder->HasFastProperties()) break;
     map = Handle<Map>(holder->map());
+    if (!CanInlinePropertyAccess(*map)) break;
     map->LookupDescriptor(*holder, *name, lookup);
     if (lookup->IsFound()) return;
   }
@@ -4397,8 +4402,8 @@
                                   LookupResult* lookup,
                                   bool is_store) {
   ASSERT(!is_store || !type->is_observed());
-  if (type->has_named_interceptor()) {
-    lookup->InterceptorResult(NULL);
+  if (!CanInlinePropertyAccess(*type)) {
+    lookup->NotFound();
     return false;
   }
   // If we directly find a field, the access can be inlined.
@@ -4541,8 +4546,7 @@
 static bool CanLoadPropertyFromPrototype(Handle<Map> map,
                                          Handle<Name> name,
                                          LookupResult* lookup) {
-  if (map->has_named_interceptor()) return false;
-  if (map->is_dictionary_map()) return false;
+  if (!CanInlinePropertyAccess(*map)) return false;
   map->LookupDescriptor(NULL, *name, lookup);
   if (lookup->IsFound()) return false;
   return true;
@@ -4634,9 +4638,8 @@
     if (current->IsJSGlobalProxy() ||
         current->IsGlobalObject() ||
         !current->IsJSObject() ||
-        JSObject::cast(current)->map()->has_named_interceptor() ||
-        JSObject::cast(current)->IsAccessCheckNeeded() ||
-        !JSObject::cast(current)->HasFastProperties()) {
+        !CanInlinePropertyAccess(JSObject::cast(current)->map()) ||
+        JSObject::cast(current)->IsAccessCheckNeeded()) {
       return false;
     }

@@ -4671,8 +4674,7 @@
     LookupResult lookup(isolate());
     if (ComputeLoadStoreField(map, name, &lookup, false) ||
         (lookup.IsCacheable() &&
-         !map->is_dictionary_map() &&
-         !map->has_named_interceptor() &&
+         CanInlinePropertyAccess(*map) &&
          (lookup.IsConstant() ||
           (!lookup.IsFound() &&
            PrototypeChainCanNeverResolve(map, name))))) {
@@ -4997,7 +4999,7 @@
   Handle<Map> map;
   if (monomorphic) {
     map = types->first();
-    if (map->is_dictionary_map()) monomorphic = false;
+    monomorphic = CanInlinePropertyAccess(*map);
   }
   if (monomorphic) {
     Handle<JSFunction> setter;
@@ -5138,7 +5140,7 @@
         map = types->first();
         // We can't generate code for a monomorphic dict mode load so
         // just pretend it is not monomorphic.
-        if (map->is_dictionary_map()) monomorphic = false;
+        monomorphic = CanInlinePropertyAccess(*map);
       }
       if (monomorphic) {
         Handle<JSFunction> getter;
@@ -5896,10 +5898,10 @@
     bool monomorphic = false;
     if (expr->IsMonomorphic()) {
       map = types->first();
-      monomorphic = !map->is_dictionary_map();
+      monomorphic = CanInlinePropertyAccess(*map);
     } else if (object->HasMonomorphicJSObjectType()) {
       map = object->GetMonomorphicJSObjectMap();
-      monomorphic = !map->is_dictionary_map();
+      monomorphic = CanInlinePropertyAccess(*map);
     }
     if (monomorphic) {
       Handle<JSFunction> getter;
@@ -7582,7 +7584,7 @@
       SmallMapList* types = prop->GetReceiverTypes();
       if (monomorphic) {
         map = types->first();
-        if (map->is_dictionary_map()) monomorphic = false;
+        monomorphic = CanInlinePropertyAccess(*map);
       }
       if (monomorphic) {
         Handle<JSFunction> getter;
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Tue Sep 3 07:34:34 2013 UTC +++ /branches/bleeding_edge/test/cctest/test-api.cc Tue Sep 3 08:55:52 2013 UTC
@@ -1828,7 +1828,17 @@
 void InterceptorSetter(Local<String> name,
                        Local<Value> value,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
-  // Intercept accesses that set certain integer values.
+ // Intercept accesses that set certain integer values, for which the name does
+  // not start with 'accessor_'.
+  String::Utf8Value utf8(name);
+  char* name_str = *utf8;
+  char prefix[] = "accessor_";
+  int i;
+  for (i = 0; name_str[i] && prefix[i]; ++i) {
+    if (name_str[i] != prefix[i]) break;
+  }
+  if (!prefix[i]) return;
+
   if (value->IsInt32() && value->Int32Value() < 10000) {
     Handle<Object> self = info.This();
     self->SetHiddenValue(name, value);
@@ -20318,5 +20328,94 @@
              "f(o);");
   ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
 }
+
+
+THREADED_TEST(CrankshaftInterceptorSetter) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope(v8::Isolate::GetCurrent());
+  Handle<FunctionTemplate> templ = FunctionTemplate::New();
+  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
+  LocalContext env;
+  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
+  CompileRun("var obj = new Obj;"
+             // Initialize fields to avoid transitions later.
+             "obj.age = 0;"
+             "obj.accessor_age = 42;"
+             "function setter(i) { this.accessor_age = i; };"
+             "function getter() { return this.accessor_age; };"
+             "function setAge(i) { obj.age = i; };"
+ "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
+             "setAge(1);"
+             "setAge(2);"
+             "setAge(3);"
+             "%OptimizeFunctionOnNextCall(setAge);"
+             "setAge(4);");
+  // All stores went through the interceptor.
+  ExpectInt32("obj.interceptor_age", 4);
+  ExpectInt32("obj.accessor_age", 42);
+}
+
+
+THREADED_TEST(CrankshaftInterceptorGetter) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope(v8::Isolate::GetCurrent());
+  Handle<FunctionTemplate> templ = FunctionTemplate::New();
+  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
+  LocalContext env;
+  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
+  CompileRun("var obj = new Obj;"
+             // Initialize fields to avoid transitions later.
+             "obj.age = 1;"
+             "obj.accessor_age = 42;"
+             "function getter() { return this.accessor_age; };"
+             "function getAge() { return obj.interceptor_age; };"
+ "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
+             "getAge();"
+             "getAge();"
+             "getAge();"
+             "%OptimizeFunctionOnNextCall(getAge);");
+  // Access through interceptor.
+  ExpectInt32("getAge()", 1);
+}
+
+
+THREADED_TEST(CrankshaftInterceptorFieldRead) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope(v8::Isolate::GetCurrent());
+  Handle<FunctionTemplate> templ = FunctionTemplate::New();
+  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
+  LocalContext env;
+  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
+  CompileRun("var obj = new Obj;"
+             "obj.__proto__.interceptor_age = 42;"
+             "obj.age = 100;"
+             "function getAge() { return obj.interceptor_age; };");
+  ExpectInt32("getAge();", 100);
+  ExpectInt32("getAge();", 100);
+  ExpectInt32("getAge();", 100);
+  CompileRun("%OptimizeFunctionOnNextCall(getAge);");
+  // Access through interceptor.
+  ExpectInt32("getAge();", 100);
+}
+
+
+THREADED_TEST(CrankshaftInterceptorFieldWrite) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::HandleScope scope(v8::Isolate::GetCurrent());
+  Handle<FunctionTemplate> templ = FunctionTemplate::New();
+  AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
+  LocalContext env;
+  env->Global()->Set(v8_str("Obj"), templ->GetFunction());
+  CompileRun("var obj = new Obj;"
+             "obj.age = 100000;"
+             "function setAge(i) { obj.age = i };"
+             "setAge(100);"
+             "setAge(101);"
+             "setAge(102);"
+             "%OptimizeFunctionOnNextCall(setAge);"
+             "setAge(103);");
+  ExpectInt32("obj.age", 100000);
+  ExpectInt32("obj.interceptor_age", 103);
+}

 #endif  // V8_OS_POSIX

--
--
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/groups/opt_out.

Reply via email to