Commit d3c4adfd authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[turbofan] Fix and rework deopt in call to super property.

This refactors the handling of calls of type Call::PROPERTY_CALL to
super properties in AstGraphBuilder::VisitCall. It ensures that the
operand stack is kept in sync with full-codegen so that deopts while
evaluating sub-expressions behave as expected.

R=rossberg@chromium.org
TEST=mjsunit/regress/regress-4521
BUG=v8:4521
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#31652}
parent dcf757a1
...@@ -2338,7 +2338,6 @@ void AstGraphBuilder::VisitCall(Call* expr) { ...@@ -2338,7 +2338,6 @@ void AstGraphBuilder::VisitCall(Call* expr) {
Node* pair = NewNode(op, current_context(), name); Node* pair = NewNode(op, current_context(), name);
callee_value = NewNode(common()->Projection(0), pair); callee_value = NewNode(common()->Projection(0), pair);
receiver_value = NewNode(common()->Projection(1), pair); receiver_value = NewNode(common()->Projection(1), pair);
PrepareFrameState(pair, expr->LookupId(), PrepareFrameState(pair, expr->LookupId(),
OutputFrameStateCombine::Push(2)); OutputFrameStateCombine::Push(2));
break; break;
...@@ -2347,58 +2346,83 @@ void AstGraphBuilder::VisitCall(Call* expr) { ...@@ -2347,58 +2346,83 @@ void AstGraphBuilder::VisitCall(Call* expr) {
Property* property = callee->AsProperty(); Property* property = callee->AsProperty();
VectorSlotPair pair = VectorSlotPair pair =
CreateVectorSlotPair(property->PropertyFeedbackSlot()); CreateVectorSlotPair(property->PropertyFeedbackSlot());
if (!property->IsSuperAccess()) { LhsKind property_type = Property::GetAssignType(property);
VisitForValue(property->obj()); switch (property_type) {
Node* object = environment()->Top(); case NAMED_PROPERTY: {
VisitForValue(property->obj());
if (property->key()->IsPropertyName()) {
FrameStateBeforeAndAfter states(this, property->obj()->id()); FrameStateBeforeAndAfter states(this, property->obj()->id());
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
Node* object = environment()->Top();
callee_value = BuildNamedLoad(object, name, pair); callee_value = BuildNamedLoad(object, name, pair);
states.AddToNode(callee_value, property->LoadId(), states.AddToNode(callee_value, property->LoadId(),
OutputFrameStateCombine::Push()); OutputFrameStateCombine::Push());
} else { // Note that a PROPERTY_CALL requires the receiver to be wrapped into
// an object for sloppy callees. However the receiver is guaranteed
// not to be null or undefined at this point.
receiver_hint = ConvertReceiverMode::kNotNullOrUndefined;
receiver_value = environment()->Pop();
flags = CALL_AS_METHOD;
break;
}
case KEYED_PROPERTY: {
VisitForValue(property->obj());
VisitForValue(property->key()); VisitForValue(property->key());
FrameStateBeforeAndAfter states(this, property->key()->id()); FrameStateBeforeAndAfter states(this, property->key()->id());
Node* key = environment()->Pop(); Node* key = environment()->Pop();
Node* object = environment()->Top();
callee_value = BuildKeyedLoad(object, key, pair); callee_value = BuildKeyedLoad(object, key, pair);
states.AddToNode(callee_value, property->LoadId(), states.AddToNode(callee_value, property->LoadId(),
OutputFrameStateCombine::Push()); OutputFrameStateCombine::Push());
// Note that a PROPERTY_CALL requires the receiver to be wrapped into
// an object for sloppy callees. However the receiver is guaranteed
// not to be null or undefined at this point.
receiver_hint = ConvertReceiverMode::kNotNullOrUndefined;
receiver_value = environment()->Pop();
flags = CALL_AS_METHOD;
break;
} }
// Note that a PROPERTY_CALL requires the receiver to be wrapped into an case NAMED_SUPER_PROPERTY: {
// object for sloppy callees. However the receiver is guaranteed not to SuperPropertyReference* super_ref =
// be null or undefined at this point. property->obj()->AsSuperPropertyReference();
receiver_hint = ConvertReceiverMode::kNotNullOrUndefined; VisitForValue(super_ref->home_object());
receiver_value = environment()->Pop(); VisitForValue(super_ref->this_var());
flags = CALL_AS_METHOD; Node* home = environment()->Peek(1);
Node* object = environment()->Top();
} else {
// TODO(mstarzinger): Cleanup this special handling for super access,
// the stack layout seems to be completely out of sync here, fix this!
VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
VisitForValue(
property->obj()->AsSuperPropertyReference()->home_object());
Node* home_object = environment()->Pop();
receiver_value = environment()->Pop();
if (property->key()->IsPropertyName()) {
FrameStateBeforeAndAfter states(this, property->obj()->id());
Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
callee_value = FrameStateBeforeAndAfter states(this, property->obj()->id());
BuildNamedSuperLoad(receiver_value, home_object, name, pair); callee_value = BuildNamedSuperLoad(object, home, name, pair);
states.AddToNode(callee_value, property->LoadId(), states.AddToNode(callee_value, property->LoadId(),
OutputFrameStateCombine::Push()); OutputFrameStateCombine::Push());
// Note that the receiver is not the target of the property load, so
} else { // it could very well be null or undefined at this point.
receiver_value = environment()->Pop();
environment()->Drop(1);
break;
}
case KEYED_SUPER_PROPERTY: {
SuperPropertyReference* super_ref =
property->obj()->AsSuperPropertyReference();
VisitForValue(super_ref->home_object());
VisitForValue(super_ref->this_var());
environment()->Push(environment()->Top()); // Duplicate this_var.
environment()->Push(environment()->Peek(2)); // Duplicate home_obj.
VisitForValue(property->key()); VisitForValue(property->key());
FrameStateBeforeAndAfter states(this, property->key()->id());
Node* key = environment()->Pop(); Node* key = environment()->Pop();
callee_value = Node* home = environment()->Pop();
BuildKeyedSuperLoad(receiver_value, home_object, key, pair); Node* object = environment()->Pop();
FrameStateBeforeAndAfter states(this, property->key()->id());
callee_value = BuildKeyedSuperLoad(object, home, key, pair);
states.AddToNode(callee_value, property->LoadId(), states.AddToNode(callee_value, property->LoadId(),
OutputFrameStateCombine::Push()); OutputFrameStateCombine::Push());
// Note that the receiver is not the target of the property load, so
// it could very well be null or undefined at this point.
receiver_value = environment()->Pop();
environment()->Drop(1);
break;
} }
case VARIABLE:
UNREACHABLE();
} }
break; break;
} }
case Call::SUPER_CALL: case Call::SUPER_CALL:
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
"use strict";
class B {
foo() { return 23 }
}
class C extends B {
bar() { return super[%DeoptimizeFunction(C.prototype.bar), "foo"]() }
}
assertEquals(23, new C().bar());
assertEquals(23, new C().bar());
%OptimizeFunctionOnNextCall(C.prototype.bar);
assertEquals(23, new C().bar());
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