[turbofan] Support for typed lowering of "prototype" load from functions.

Add initial support to optimize certain "prototype" loads from known
JSFunctions which have a prototype. This includes an appropriate typing
rule plus a matching rule for typed lowering.

R=jarin@chromium.org

Review URL: https://codereview.chromium.org/1482213002

Cr-Commit-Position: refs/heads/master@{#32390}
This commit is contained in:
bmeurer 2015-11-30 00:41:59 -08:00 committed by Commit bot
parent 7730edcc12
commit f7226a798a
3 changed files with 73 additions and 1 deletions

View File

@ -975,6 +975,27 @@ Reduction JSTypedLowering::ReduceJSLoadNamed(Node* node) {
ReplaceWithValue(node, value, effect);
return Replace(value);
}
// Optimize "prototype" property of functions.
if (name.is_identical_to(factory()->prototype_string()) &&
receiver_type->IsConstant() &&
receiver_type->AsConstant()->Value()->IsJSFunction()) {
// TODO(turbofan): This lowering might not kick in if we ever lower
// the C++ accessor for "prototype" in an earlier optimization pass.
Handle<JSFunction> function =
Handle<JSFunction>::cast(receiver_type->AsConstant()->Value());
if (function->has_initial_map()) {
// We need to add a code dependency on the initial map of the {function}
// in order to be notified about changes to the "prototype" of {function},
// so it doesn't make sense to continue unless deoptimization is enabled.
if (!(flags() & kDeoptimizationEnabled)) return NoChange();
Handle<Map> initial_map(function->initial_map(), isolate());
dependencies()->AssumeInitialMapCantChange(initial_map);
Node* value =
jsgraph()->Constant(handle(initial_map->prototype(), isolate()));
ReplaceWithValue(node, value);
return Replace(value);
}
}
return NoChange();
}

View File

@ -1262,7 +1262,37 @@ Type* Typer::Visitor::TypeJSLoadProperty(Node* node) {
}
Type* Typer::Visitor::TypeJSLoadNamed(Node* node) { return Type::Any(); }
Type* Typer::Visitor::TypeJSLoadNamed(Node* node) {
Factory* const f = isolate()->factory();
Handle<Name> name = NamedAccessOf(node->op()).name();
if (name.is_identical_to(f->prototype_string())) {
Type* receiver = Operand(node, 0);
if (receiver->Is(Type::None())) return Type::None();
if (receiver->IsConstant() &&
receiver->AsConstant()->Value()->IsJSFunction()) {
Handle<JSFunction> function =
Handle<JSFunction>::cast(receiver->AsConstant()->Value());
if (function->has_prototype()) {
// We need to add a code dependency on the initial map of the {function}
// in order to be notified about changes to "prototype" of {function},
// so we can only infer a constant type if deoptimization is enabled.
if (flags() & kDeoptimizationEnabled) {
JSFunction::EnsureHasInitialMap(function);
Handle<Map> initial_map(function->initial_map(), isolate());
dependencies()->AssumeInitialMapCantChange(initial_map);
return Type::Constant(handle(initial_map->prototype(), isolate()),
zone());
}
}
} else if (receiver->IsClass() &&
receiver->AsClass()->Map()->IsJSFunctionMap()) {
Handle<Map> map = receiver->AsClass()->Map();
return map->has_non_instance_prototype() ? Type::Primitive(zone())
: Type::Receiver(zone());
}
}
return Type::Any();
}
Type* Typer::Visitor::TypeJSLoadGlobal(Node* node) { return Type::Any(); }

View File

@ -952,6 +952,27 @@ TEST_F(JSTypedLoweringTest, JSLoadNamedStringLength) {
}
TEST_F(JSTypedLoweringTest, JSLoadNamedFunctionPrototype) {
VectorSlotPair feedback;
Handle<Name> name = factory()->prototype_string();
Handle<JSFunction> function = isolate()->object_function();
Handle<JSObject> function_prototype(JSObject::cast(function->prototype()));
Node* const receiver = Parameter(Type::Constant(function, zone()), 0);
Node* const vector = Parameter(Type::Internal(), 1);
Node* const context = Parameter(Type::Internal(), 2);
Node* const effect = graph()->start();
Node* const control = graph()->start();
TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
Reduction const r = Reduce(
graph()->NewNode(javascript()->LoadNamed(language_mode, name, feedback),
receiver, vector, context, EmptyFrameState(),
EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsHeapConstant(function_prototype));
}
}
// -----------------------------------------------------------------------------
// JSAdd