Added Crankshaft support for setters.

Refactored ComputeLoadStoreField a bit on the way to clarify a bit what it
actually does.

Review URL: https://chromiumcodereview.appspot.com/10692187

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12072 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 70a61830
...@@ -4911,10 +4911,17 @@ static bool ComputeLoadStoreField(Handle<Map> type, ...@@ -4911,10 +4911,17 @@ static bool ComputeLoadStoreField(Handle<Map> type,
Handle<String> name, Handle<String> name,
LookupResult* lookup, LookupResult* lookup,
bool is_store) { bool is_store) {
type->LookupTransitionOrDescriptor(NULL, *name, lookup); // If we directly find a field, the access can be inlined.
type->LookupDescriptor(NULL, *name, lookup);
if (lookup->IsField()) return true; if (lookup->IsField()) return true;
return is_store &&
lookup->IsTransitionToField(*type) && // For a load, we are out of luck if there is no such field.
if (!is_store) return false;
// 2nd chance: A store into a non-existent field can still be inlined if we
// have a matching transition and some room left in the object.
type->LookupTransition(NULL, *name, lookup);
return lookup->IsTransitionToField(*type) &&
(type->unused_property_fields() > 0); (type->unused_property_fields() > 0);
} }
...@@ -5007,21 +5014,71 @@ HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, ...@@ -5007,21 +5014,71 @@ HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
} }
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());
map->LookupDescriptor(*holder, *name, lookup);
if (lookup->IsFound()) return;
}
lookup->NotFound();
}
HInstruction* HGraphBuilder::BuildCallSetter(HValue* obj,
Handle<String> name,
HValue* value,
Handle<Map> map,
Handle<Object> callback,
Handle<JSObject> holder) {
if (!callback->IsAccessorPair()) {
return BuildStoreNamedGeneric(obj, name, value);
}
Handle<Object> setter(Handle<AccessorPair>::cast(callback)->setter());
Handle<JSFunction> function(Handle<JSFunction>::cast(setter));
AddCheckConstantFunction(holder, obj, map, true);
AddInstruction(new(zone()) HPushArgument(obj));
AddInstruction(new(zone()) HPushArgument(value));
return new(zone()) HCallConstantFunction(function, 2);
}
HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
HValue* value, HValue* value,
Handle<Map> type, Handle<Map> type,
Expression* key) { Expression* key) {
// If we don't know the monomorphic type, do a generic store.
Handle<String> name = Handle<String>::cast(key->AsLiteral()->handle()); Handle<String> name = Handle<String>::cast(key->AsLiteral()->handle());
ASSERT(!name.is_null()); if (type.is_null()) return BuildStoreNamedGeneric(object, name, value);
// Handle a store to a known field.
LookupResult lookup(isolate()); LookupResult lookup(isolate());
bool is_monomorphic = !type.is_null() && if (ComputeLoadStoreField(type, name, &lookup, true)) {
ComputeLoadStoreField(type, name, &lookup, true); // true = needs smi and map check.
return BuildStoreNamedField(object, name, value, type, &lookup, true);
}
// Handle a known setter directly in the receiver.
type->LookupDescriptor(NULL, *name, &lookup);
if (lookup.IsPropertyCallbacks()) {
Handle<Object> callback(lookup.GetValueFromMap(*type));
Handle<JSObject> holder;
return BuildCallSetter(object, name, value, type, callback, holder);
}
return is_monomorphic // Handle a known setter somewhere in the prototype chain.
? BuildStoreNamedField(object, name, value, type, &lookup, LookupInPrototypes(type, name, &lookup);
true) // Needs smi and map check. if (lookup.IsPropertyCallbacks()) {
: BuildStoreNamedGeneric(object, name, value); Handle<Object> callback(lookup.GetValue());
Handle<JSObject> holder(lookup.holder());
return BuildCallSetter(object, name, value, type, callback, holder);
}
// No luck, do a generic store.
return BuildStoreNamedGeneric(object, name, value);
} }
...@@ -5597,20 +5654,6 @@ HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, ...@@ -5597,20 +5654,6 @@ HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj,
} }
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());
map->LookupDescriptor(*holder, *name, lookup);
if (lookup->IsFound()) return;
}
lookup->NotFound();
}
HInstruction* HGraphBuilder::BuildCallGetter(HValue* obj, HInstruction* HGraphBuilder::BuildCallGetter(HValue* obj,
Property* expr, Property* expr,
Handle<Map> map, Handle<Map> map,
......
...@@ -1149,6 +1149,12 @@ class HGraphBuilder: public AstVisitor { ...@@ -1149,6 +1149,12 @@ class HGraphBuilder: public AstVisitor {
Property* prop, Property* prop,
Handle<Map> map, Handle<Map> map,
Handle<String> name); Handle<String> name);
HInstruction* BuildCallSetter(HValue* object,
Handle<String> name,
HValue* value,
Handle<Map> map,
Handle<Object> callback,
Handle<JSObject> holder);
HInstruction* BuildStoreNamed(HValue* object, HInstruction* BuildStoreNamed(HValue* object,
HValue* value, HValue* value,
Handle<Map> type, Handle<Map> type,
......
...@@ -66,3 +66,25 @@ assertEquals(111, boo(C)); ...@@ -66,3 +66,25 @@ assertEquals(111, boo(C));
ToDictionaryMode(B); ToDictionaryMode(B);
%OptimizeFunctionOnNextCall(boo); %OptimizeFunctionOnNextCall(boo);
assertEquals(111, boo(C)); assertEquals(111, boo(C));
// And once more for setters...
A = {};
Object.defineProperty(A, "huh", { set: function(x) { assertUnreachable(); }});
B = Object.create(A);
var setterValue;
Object.defineProperty(B, "huh", { set: function(x) { setterValue = x; }});
C = Object.create(B);
function fuu(x) {
setterValue = 222;
x.huh = 111;
return setterValue;
}
assertEquals(111, fuu(C));
assertEquals(111, fuu(C));
ToDictionaryMode(B);
%OptimizeFunctionOnNextCall(fuu);
assertEquals(111, fuu(C));
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