Commit 1270caed authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Unify function prototype constant folding.

Up until now we had two places where we did the function prototype
folding, once in the Typer and once in JSTypedLowering. Put this logic
into JSNativeContextSpecialization instead.

R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/1965293002
Cr-Commit-Position: refs/heads/master@{#36157}
parent 0cb89c26
......@@ -457,8 +457,33 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
NamedAccess const& p = NamedAccessOf(node->op());
Node* const receiver = NodeProperties::GetValueInput(node, 0);
Node* const value = jsgraph()->Dead();
// Check if we have a constant receiver.
HeapObjectMatcher m(receiver);
if (m.HasValue()) {
// Optimize "prototype" property of functions.
if (m.Value()->IsJSFunction() &&
p.name().is_identical_to(factory()->prototype_string())) {
Handle<JSFunction> function = Handle<JSFunction>::cast(m.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)) {
Handle<Map> initial_map(function->initial_map(), isolate());
dependencies()->AssumeInitialMapCantChange(initial_map);
Handle<Object> prototype(initial_map->prototype(), isolate());
Node* value = jsgraph()->Constant(prototype);
ReplaceWithValue(node, value);
return Replace(value);
}
}
}
}
// Extract receiver maps from the LOAD_IC using the LoadICNexus.
if (!p.feedback().IsValid()) return NoChange();
LoadICNexus nexus(p.feedback().vector(), p.feedback().slot());
......
......@@ -936,27 +936,6 @@ 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();
}
......
......@@ -1347,34 +1347,6 @@ Type* Typer::Visitor::TypeJSLoadProperty(Node* node) {
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()
: Type::Receiver();
}
}
return Type::Any();
}
......
......@@ -814,24 +814,6 @@ 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();
Reduction const r = Reduce(graph()->NewNode(
javascript()->LoadNamed(name, feedback), receiver, vector, context,
EmptyFrameState(), EmptyFrameState(), effect, control));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsHeapConstant(function_prototype));
}
// -----------------------------------------------------------------------------
// JSAdd
......
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