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.