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

[turbofan] Implement super call support in TurboFan.

R=rossberg@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#29696}
parent c6d42c7d
......@@ -2513,7 +2513,7 @@ void AstGraphBuilder::VisitCallSuper(Call* expr) {
ZoneList<Expression*>* args = expr->arguments();
VisitForValues(args);
// Original receiver is loaded from the {new.target} variable.
// Original constructor is loaded from the {new.target} variable.
VisitForValue(super->new_target_var());
// Create node to perform the super call.
......@@ -2521,14 +2521,10 @@ void AstGraphBuilder::VisitCallSuper(Call* expr) {
Node* value = ProcessArguments(call, args->length() + 2);
PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
// TODO(mstarzinger): It sure would be nice if this were desugared. Also we
// are still missing the hole-check in the assignment below, fix that.
// TODO(mstarzinger): It sure would be nice if this were desugared.
FrameStateBeforeAndAfter states(this, BailoutId::None());
BuildVariableAssignment(super->this_var()->var(), value, Token::INIT_CONST,
VectorSlotPair(), BailoutId::None(), states);
// TODO(mstarzinger): Remove bailout once lowering is correct.
SetStackOverflow();
VectorSlotPair(), expr->id(), states);
ast_context()->ProduceValue(value);
}
......@@ -2541,7 +2537,7 @@ void AstGraphBuilder::VisitCallNew(CallNew* expr) {
ZoneList<Expression*>* args = expr->arguments();
VisitForValues(args);
// Original receiver is the same as the callee.
// Original constructor is the same as the callee.
environment()->Push(environment()->Peek(args->length()));
// Create node to perform the construct call.
......@@ -3272,9 +3268,9 @@ Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
}
Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
Node* not_hole,
BailoutId bailout_id) {
Node* AstGraphBuilder::BuildHoleCheckThenThrow(Node* value, Variable* variable,
Node* not_hole,
BailoutId bailout_id) {
IfBuilder hole_check(this);
Node* the_hole = jsgraph()->TheHoleConstant();
Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
......@@ -3289,6 +3285,23 @@ Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
}
Node* AstGraphBuilder::BuildHoleCheckElseThrow(Node* value, Variable* variable,
Node* for_hole,
BailoutId bailout_id) {
IfBuilder hole_check(this);
Node* the_hole = jsgraph()->TheHoleConstant();
Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
hole_check.If(check);
hole_check.Then();
environment()->Push(for_hole);
hole_check.Else();
Node* error = BuildThrowReferenceError(variable, bailout_id);
environment()->Push(error);
hole_check.End();
return environment()->Pop();
}
Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name,
BailoutId bailout_id) {
IfBuilder prototype_check(this);
......@@ -3358,7 +3371,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
if (value->op() == the_hole->op()) {
value = BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi || variable->is_this()) {
value = BuildHoleCheckThrow(value, variable, value, bailout_id);
value = BuildHoleCheckThenThrow(value, variable, value, bailout_id);
}
}
return value;
......@@ -3379,7 +3392,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
value = BuildHoleCheckSilent(value, undefined, value);
} else if (mode == LET || mode == CONST) {
// Perform check for uninitialized let/const variables.
value = BuildHoleCheckThrow(value, variable, value, bailout_id);
value = BuildHoleCheckThenThrow(value, variable, value, bailout_id);
}
return value;
}
......@@ -3410,7 +3423,7 @@ Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
value = BuildHoleCheckSilent(value, undefined, value);
} else if (local_mode == LET || local_mode == CONST) {
// Perform check for uninitialized let/const variables.
value = BuildHoleCheckThrow(value, local, value, bailout_id);
value = BuildHoleCheckThenThrow(value, local, value, bailout_id);
}
} else if (mode == DYNAMIC) {
uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
......@@ -3519,7 +3532,15 @@ Node* AstGraphBuilder::BuildVariableAssignment(
if (current->op() == the_hole->op()) {
value = BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) {
value = BuildHoleCheckThrow(current, variable, value, bailout_id);
value = BuildHoleCheckThenThrow(current, variable, value, bailout_id);
}
} else if (mode == CONST && op == Token::INIT_CONST) {
// Perform an initialization check for const {this} variables.
// Note that the {this} variable is the only const variable being able
// to trigger bind operations outside the TDZ, via {super} calls.
Node* current = environment()->Lookup(variable);
if (current->op() != the_hole->op() && variable->is_this()) {
value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
}
} else if (mode == CONST && op != Token::INIT_CONST) {
// Assignment to const is exception in all modes.
......@@ -3527,7 +3548,7 @@ Node* AstGraphBuilder::BuildVariableAssignment(
if (current->op() == the_hole->op()) {
return BuildThrowReferenceError(variable, bailout_id);
} else if (value->opcode() == IrOpcode::kPhi) {
BuildHoleCheckThrow(current, variable, value, bailout_id);
BuildHoleCheckThenThrow(current, variable, value, bailout_id);
}
return BuildThrowConstAssignError(bailout_id);
}
......@@ -3555,13 +3576,23 @@ Node* AstGraphBuilder::BuildVariableAssignment(
const Operator* op =
javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context());
value = BuildHoleCheckThrow(current, variable, value, bailout_id);
value = BuildHoleCheckThenThrow(current, variable, value, bailout_id);
} else if (mode == CONST && op == Token::INIT_CONST) {
// Perform an initialization check for const {this} variables.
// Note that the {this} variable is the only const variable being able
// to trigger bind operations outside the TDZ, via {super} calls.
if (variable->is_this()) {
const Operator* op =
javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context());
value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
}
} else if (mode == CONST && op != Token::INIT_CONST) {
// Assignment to const is exception in all modes.
const Operator* op =
javascript()->LoadContext(depth, variable->index(), false);
Node* current = NewNode(op, current_context());
BuildHoleCheckThrow(current, variable, value, bailout_id);
BuildHoleCheckThenThrow(current, variable, value, bailout_id);
return BuildThrowConstAssignError(bailout_id);
}
const Operator* op = javascript()->StoreContext(depth, variable->index());
......
......@@ -347,8 +347,10 @@ class AstGraphBuilder : public AstVisitor {
// Builders for dynamic hole-checks at runtime.
Node* BuildHoleCheckSilent(Node* value, Node* for_hole, Node* not_hole);
Node* BuildHoleCheckThrow(Node* value, Variable* var, Node* not_hole,
BailoutId bailout_id);
Node* BuildHoleCheckThenThrow(Node* value, Variable* var, Node* not_hole,
BailoutId bailout_id);
Node* BuildHoleCheckElseThrow(Node* value, Variable* var, Node* for_hole,
BailoutId bailout_id);
// Builders for conditional errors.
Node* BuildThrowIfStaticPrototype(Node* name, BailoutId bailout_id);
......
......@@ -161,6 +161,11 @@ void ALAA::VisitProperty(Property* e) {
void ALAA::VisitCall(Call* e) {
Visit(e->expression());
VisitExpressions(e->arguments());
// TODO(mstarzinger): It sure would be nice if this were desugared.
if (e->GetCallType(isolate()) == Call::SUPER_CALL) {
SuperCallReference* super = e->expression()->AsSuperCallReference();
AnalyzeAssignment(super->this_var()->var());
}
}
......
......@@ -537,7 +537,7 @@ void JSGenericLowering::LowerJSCreateCatchContext(Node* node) {
void JSGenericLowering::LowerJSCallConstruct(Node* node) {
int arity = OpParameter<int>(node);
CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
CallConstructStub stub(isolate(), SUPER_CONSTRUCTOR_CALL);
CallInterfaceDescriptor d = stub.GetCallInterfaceDescriptor();
CallDescriptor::Flags flags = AdjustFrameStatesForCall(node);
CallDescriptor* desc =
......
......@@ -2181,6 +2181,47 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44);
})();
(function TestSuperCallInLoop() {
'use strict';
class Base {
constructor(x) {
this.x = x;
}
}
class Derived extends Base {
constructor(x, n) {
for (var i = 0; i < n; ++i) {
super(x);
}
}
}
let o = new Derived(23, 1);
assertEquals(23, o.x);
assertInstanceof(o, Derived);
assertThrows("new Derived(42, 0)", ReferenceError);
assertThrows("new Derived(65, 2)", ReferenceError);
})();
(function TestSuperCallReentrant() {
'use strict';
class Base {
constructor(fun) {
this.x = fun();
}
}
class Derived extends Base {
constructor(x) {
let f = () => super(() => x)
super(f);
}
}
assertThrows("new Derived(23)", ReferenceError);
})();
(function TestSuperCallSpreadInEval() {
'use strict';
class Base {
......
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