Commit c41cb4be authored by verwaest@chromium.org's avatar verwaest@chromium.org

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
parent d1c0d6b3
......@@ -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> map,
Handle<String> name,
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 @@ static bool ComputeLoadStoreField(Handle<Map> 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> 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 @@ 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> 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 @@ 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<JSFunction> 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<JSFunction> 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<JSFunction> getter;
......
......@@ -1828,7 +1828,17 @@ void InterceptorGetter(Local<String> name,
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);
......@@ -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<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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment