From c41cb4be44f1bf1c3d2589c332612807f6b17fc8 Mon Sep 17 00:00:00 2001 From: "verwaest@chromium.org" Date: Tue, 3 Sep 2013 08:55:52 +0000 Subject: [PATCH] Fix interceptor handling in crankshaft. R=dcarney@chromium.org Review URL: https://chromiumcodereview.appspot.com/23614011 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16495 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/hydrogen.cc | 32 ++++++++------- test/cctest/test-api.cc | 101 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 16 deletions(-) diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 0b1fe09..c42d035 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -4003,13 +4003,18 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { } +static bool CanInlinePropertyAccess(Map* type) { + return !type->is_dictionary_map() && !type->has_named_interceptor(); +} + + static void LookupInPrototypes(Handle map, Handle name, LookupResult* lookup) { while (map->prototype()->IsJSObject()) { Handle holder(JSObject::cast(map->prototype())); - if (!holder->HasFastProperties()) break; map = Handle(holder->map()); + if (!CanInlinePropertyAccess(*map)) break; map->LookupDescriptor(*holder, *name, lookup); if (lookup->IsFound()) return; } @@ -4397,8 +4402,8 @@ static bool ComputeLoadStoreField(Handle type, 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 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( static bool CanLoadPropertyFromPrototype(Handle map, Handle 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 @@ static bool PrototypeChainCanNeverResolve( 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 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( 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 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, Handle map; if (monomorphic) { map = types->first(); - if (map->is_dictionary_map()) monomorphic = false; + monomorphic = CanInlinePropertyAccess(*map); } if (monomorphic) { Handle setter; @@ -5138,7 +5140,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { 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 getter; @@ -5896,10 +5898,10 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { 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 getter; @@ -7582,7 +7584,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { SmallMapList* types = prop->GetReceiverTypes(); if (monomorphic) { map = types->first(); - if (map->is_dictionary_map()) monomorphic = false; + monomorphic = CanInlinePropertyAccess(*map); } if (monomorphic) { Handle getter; diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index c90fea0..4468e65 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -1828,7 +1828,17 @@ void InterceptorGetter(Local name, void InterceptorSetter(Local name, Local value, const v8::PropertyCallbackInfo& 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 self = info.This(); self->SetHiddenValue(name, value); @@ -20319,4 +20329,93 @@ THREADED_TEST(Regress256330) { ExpectBoolean("%GetOptimizationStatus(f) != 2", true); } + +THREADED_TEST(CrankshaftInterceptorSetter) { + i::FLAG_allow_natives_syntax = true; + v8::HandleScope scope(v8::Isolate::GetCurrent()); + Handle 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 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 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 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 -- 2.7.4