From 07dc66dcd5d9bc266915d67142425dd92e1373ad Mon Sep 17 00:00:00 2001 From: mstarzinger Date: Thu, 16 Jul 2015 07:26:20 -0700 Subject: [PATCH] Represent implicit 'this' binding by 'super' in AST. This makes the implicit initializing assignment to 'this' performed after a super constructor call explicit in the AST. It removes the need to handle the special case where a CallExpression behaves like a AssignmentExpression from various AstVisitor implementations. R=rossberg@chromium.org Review URL: https://codereview.chromium.org/1226123010 Cr-Commit-Position: refs/heads/master@{#29705} --- src/arm/full-codegen-arm.cc | 40 +++++++++----------- src/arm64/full-codegen-arm64.cc | 38 ++++++++----------- src/ast.cc | 6 +++ src/ast.h | 4 ++ src/compiler/ast-graph-builder.cc | 12 ++---- src/compiler/ast-loop-assignment-analyzer.cc | 5 --- src/full-codegen.h | 3 -- src/ia32/full-codegen-ia32.cc | 39 ++++++++----------- src/mips/full-codegen-mips.cc | 40 +++++++++----------- src/mips64/full-codegen-mips64.cc | 40 +++++++++----------- src/ppc/full-codegen-ppc.cc | 40 +++++++++----------- src/preparser.h | 39 ++++++++++++++++--- src/x64/full-codegen-x64.cc | 38 ++++++++----------- src/x87/full-codegen-x87.cc | 39 ++++++++----------- test/mjsunit/harmony/super.js | 21 ++++++---- 15 files changed, 192 insertions(+), 212 deletions(-) diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 4b74afd89..421b7f33b 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -2000,7 +2000,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ Assignment"); SetExpressionPosition(expr, INSERT_BREAK); @@ -2677,7 +2677,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackVectorICSlot slot) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); Property* prop = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(prop); @@ -2825,6 +2825,20 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ bind(&const_error); __ CallRuntime(Runtime::kThrowConstAssignError, 0); + } else if (var->is_this() && op == Token::INIT_CONST) { + // Initializing assignment to const {this} needs a write barrier. + DCHECK(var->IsStackAllocated() || var->IsContextSlot()); + Label uninitialized_this; + MemOperand location = VarOperand(var, r1); + __ ldr(r3, location); + __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); + __ b(eq, &uninitialized_this); + __ mov(r0, Operand(var->name())); + __ Push(r0); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&uninitialized_this); + EmitStoreToStackLocalOrContextSlot(var, location); + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -3176,22 +3190,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitInitializeThisAfterSuper( - SuperCallReference* super_ref, FeedbackVectorICSlot slot) { - Variable* this_var = super_ref->this_var()->var(); - GetVar(r1, this_var); - __ CompareRoot(r1, Heap::kTheHoleValueRootIndex); - Label uninitialized_this; - __ b(eq, &uninitialized_this); - __ mov(r0, Operand(this_var->name())); - __ Push(r0); - __ CallRuntime(Runtime::kThrowReferenceError, 1); - __ bind(&uninitialized_this); - - EmitVariableAssignment(this_var, Token::INIT_CONST, slot); -} - - // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { VariableProxy* callee = expr->expression()->AsVariableProxy(); @@ -3413,7 +3411,6 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { RecordJSReturnSite(expr); - EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot()); context()->Plug(r0); } @@ -4744,9 +4741,6 @@ void FullCodeGenerator::EmitCallSuperWithSpread(CallRuntime* expr) { // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, r0); - - // TODO(mvstanton): with FLAG_vector_stores this needs a slot id. - EmitInitializeThisAfterSuper(super_call_ref); } @@ -4944,7 +4938,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ CountOperation"); diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index 825eed5be..c95bbafec 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -1977,7 +1977,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ Assignment"); SetExpressionPosition(expr, INSERT_BREAK); @@ -2359,7 +2359,7 @@ void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit, void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackVectorICSlot slot) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); Property* prop = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(prop); @@ -2508,6 +2508,19 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ Bind(&const_error); __ CallRuntime(Runtime::kThrowConstAssignError, 0); + } else if (var->is_this() && op == Token::INIT_CONST) { + // Initializing assignment to const {this} needs a write barrier. + DCHECK(var->IsStackAllocated() || var->IsContextSlot()); + Label uninitialized_this; + MemOperand location = VarOperand(var, x1); + __ Ldr(x10, location); + __ JumpIfRoot(x10, Heap::kTheHoleValueRootIndex, &uninitialized_this); + __ Mov(x0, Operand(var->name())); + __ Push(x0); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&uninitialized_this); + EmitStoreToStackLocalOrContextSlot(var, location); + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -2866,21 +2879,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitInitializeThisAfterSuper( - SuperCallReference* super_ref, FeedbackVectorICSlot slot) { - Variable* this_var = super_ref->this_var()->var(); - GetVar(x1, this_var); - Label uninitialized_this; - __ JumpIfRoot(x1, Heap::kTheHoleValueRootIndex, &uninitialized_this); - __ Mov(x0, Operand(this_var->name())); - __ Push(x0); - __ CallRuntime(Runtime::kThrowReferenceError, 1); - __ bind(&uninitialized_this); - - EmitVariableAssignment(this_var, Token::INIT_CONST, slot); -} - - // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { VariableProxy* callee = expr->expression()->AsVariableProxy(); @@ -3103,7 +3101,6 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { RecordJSReturnSite(expr); - EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot()); context()->Plug(x0); } @@ -4434,9 +4431,6 @@ void FullCodeGenerator::EmitCallSuperWithSpread(CallRuntime* expr) { // Restore context register. __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, x0); - - // TODO(mvstanton): with FLAG_vector_stores this needs a slot id. - EmitInitializeThisAfterSuper(super_call_ref); } @@ -4632,7 +4626,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ CountOperation"); diff --git a/src/ast.cc b/src/ast.cc index 93cb6c09b..9dd825a6f 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -59,6 +59,12 @@ bool Expression::IsUndefinedLiteral(Isolate* isolate) const { } +bool Expression::IsValidReferenceExpressionOrThis() const { + return IsValidReferenceExpression() || + (IsVariableProxy() && AsVariableProxy()->is_this()); +} + + VariableProxy::VariableProxy(Zone* zone, Variable* var, int start_position, int end_position) : Expression(zone, start_position), diff --git a/src/ast.h b/src/ast.h index b1a634edb..ee019e8f0 100644 --- a/src/ast.h +++ b/src/ast.h @@ -339,6 +339,7 @@ class Expression : public AstNode { kTest }; + // True iff the expression is a valid reference expression. virtual bool IsValidReferenceExpression() const { return false; } // Helpers for ToBoolean conversion. @@ -362,6 +363,9 @@ class Expression : public AstNode { // True if we can prove that the expression is the undefined literal. bool IsUndefinedLiteral(Isolate* isolate) const; + // True iff the expression is a valid target for an assignment. + bool IsValidReferenceExpressionOrThis() const; + // Expression type bounds Bounds bounds() const { return bounds_; } void set_bounds(Bounds bounds) { bounds_ = bounds; } diff --git a/src/compiler/ast-graph-builder.cc b/src/compiler/ast-graph-builder.cc index 0c0bb02ea..c105f2c22 100644 --- a/src/compiler/ast-graph-builder.cc +++ b/src/compiler/ast-graph-builder.cc @@ -2016,7 +2016,7 @@ void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value, const VectorSlotPair& feedback, BailoutId bailout_id) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); // Left-hand side can only be a property, a global or a variable slot. Property* property = expr->AsProperty(); @@ -2090,7 +2090,7 @@ void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value, void AstGraphBuilder::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); // Left-hand side can only be a property, a global or a variable slot. Property* property = expr->target()->AsProperty(); @@ -2520,12 +2520,6 @@ void AstGraphBuilder::VisitCallSuper(Call* expr) { const Operator* call = javascript()->CallConstruct(args->length() + 2); 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. - FrameStateBeforeAndAfter states(this, BailoutId::None()); - BuildVariableAssignment(super->this_var()->var(), value, Token::INIT_CONST, - VectorSlotPair(), expr->id(), states); - ast_context()->ProduceValue(value); } @@ -2627,7 +2621,7 @@ void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); // Left-hand side can only be a property, a global or a variable slot. Property* property = expr->expression()->AsProperty(); diff --git a/src/compiler/ast-loop-assignment-analyzer.cc b/src/compiler/ast-loop-assignment-analyzer.cc index e0a92a464..61ed4f27c 100644 --- a/src/compiler/ast-loop-assignment-analyzer.cc +++ b/src/compiler/ast-loop-assignment-analyzer.cc @@ -161,11 +161,6 @@ 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()); - } } diff --git a/src/full-codegen.h b/src/full-codegen.h index ccc10e061..88a88f45b 100644 --- a/src/full-codegen.h +++ b/src/full-codegen.h @@ -644,9 +644,6 @@ class FullCodeGenerator: public AstVisitor { FeedbackVectorICSlot slot = FeedbackVectorICSlot::Invalid()); void EmitLoadSuperConstructor(SuperCallReference* super_call_ref); - void EmitInitializeThisAfterSuper( - SuperCallReference* super_call_ref, - FeedbackVectorICSlot slot = FeedbackVectorICSlot::Invalid()); void CallIC(Handle code, TypeFeedbackId id = TypeFeedbackId::None()); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index a317977f3..d2b0c1079 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1927,7 +1927,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ Assignment"); SetExpressionPosition(expr, INSERT_BREAK); @@ -2584,7 +2584,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackVectorICSlot slot) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); Property* prop = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(prop); @@ -2726,6 +2726,19 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ bind(&const_error); __ CallRuntime(Runtime::kThrowConstAssignError, 0); + } else if (var->is_this() && op == Token::INIT_CONST) { + // Initializing assignment to const {this} needs a write barrier. + DCHECK(var->IsStackAllocated() || var->IsContextSlot()); + Label uninitialized_this; + MemOperand location = VarOperand(var, ecx); + __ mov(edx, location); + __ cmp(edx, isolate()->factory()->the_hole_value()); + __ j(equal, &uninitialized_this); + __ push(Immediate(var->name())); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&uninitialized_this); + EmitStoreToStackLocalOrContextSlot(var, location); + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -3068,22 +3081,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitInitializeThisAfterSuper( - SuperCallReference* super_call_ref, FeedbackVectorICSlot slot) { - Variable* this_var = super_call_ref->this_var()->var(); - GetVar(ecx, this_var); - __ cmp(ecx, isolate()->factory()->the_hole_value()); - - Label uninitialized_this; - __ j(equal, &uninitialized_this); - __ push(Immediate(this_var->name())); - __ CallRuntime(Runtime::kThrowReferenceError, 1); - __ bind(&uninitialized_this); - - EmitVariableAssignment(this_var, Token::INIT_CONST, slot); -} - - // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { VariableProxy* callee = expr->expression()->AsVariableProxy(); @@ -3299,7 +3296,6 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { RecordJSReturnSite(expr); - EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot()); context()->Plug(eax); } @@ -4675,9 +4671,6 @@ void FullCodeGenerator::EmitCallSuperWithSpread(CallRuntime* expr) { // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, eax); - - // TODO(mvstanton): with FLAG_vector_stores this needs a slot id. - EmitInitializeThisAfterSuper(super_call_ref); } @@ -4876,7 +4869,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ CountOperation"); diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index 71acc700c..9b36719e3 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -1993,7 +1993,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ Assignment"); SetExpressionPosition(expr, INSERT_BREAK); @@ -2662,7 +2662,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackVectorICSlot slot) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); Property* prop = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(prop); @@ -2811,6 +2811,20 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ bind(&const_error); __ CallRuntime(Runtime::kThrowConstAssignError, 0); + } else if (var->is_this() && op == Token::INIT_CONST) { + // Initializing assignment to const {this} needs a write barrier. + DCHECK(var->IsStackAllocated() || var->IsContextSlot()); + Label uninitialized_this; + MemOperand location = VarOperand(var, a1); + __ lw(a3, location); + __ LoadRoot(at, Heap::kTheHoleValueRootIndex); + __ Branch(&uninitialized_this, eq, a3, Operand(at)); + __ li(a0, Operand(var->name())); + __ Push(a0); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&uninitialized_this); + EmitStoreToStackLocalOrContextSlot(var, location); + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -3160,22 +3174,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitInitializeThisAfterSuper( - SuperCallReference* super_ref, FeedbackVectorICSlot slot) { - Variable* this_var = super_ref->this_var()->var(); - GetVar(a1, this_var); - __ LoadRoot(at, Heap::kTheHoleValueRootIndex); - Label uninitialized_this; - __ Branch(&uninitialized_this, eq, a1, Operand(at)); - __ li(a0, Operand(this_var->name())); - __ Push(a0); - __ CallRuntime(Runtime::kThrowReferenceError, 1); - __ bind(&uninitialized_this); - - EmitVariableAssignment(this_var, Token::INIT_CONST, slot); -} - - // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { VariableProxy* callee = expr->expression()->AsVariableProxy(); @@ -3395,7 +3393,6 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { RecordJSReturnSite(expr); - EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot()); context()->Plug(v0); } @@ -4761,9 +4758,6 @@ void FullCodeGenerator::EmitCallSuperWithSpread(CallRuntime* expr) { // Restore context register. __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, v0); - - // TODO(mvstanton): with FLAG_vector_stores this needs a slot id. - EmitInitializeThisAfterSuper(super_call_ref); } @@ -4961,7 +4955,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ CountOperation"); diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc index ebd9abe81..1102b9e28 100644 --- a/src/mips64/full-codegen-mips64.cc +++ b/src/mips64/full-codegen-mips64.cc @@ -1989,7 +1989,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ Assignment"); SetExpressionPosition(expr, INSERT_BREAK); @@ -2659,7 +2659,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackVectorICSlot slot) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); Property* prop = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(prop); @@ -2808,6 +2808,20 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ bind(&const_error); __ CallRuntime(Runtime::kThrowConstAssignError, 0); + } else if (var->is_this() && op == Token::INIT_CONST) { + // Initializing assignment to const {this} needs a write barrier. + DCHECK(var->IsStackAllocated() || var->IsContextSlot()); + Label uninitialized_this; + MemOperand location = VarOperand(var, a1); + __ ld(a3, location); + __ LoadRoot(at, Heap::kTheHoleValueRootIndex); + __ Branch(&uninitialized_this, eq, a3, Operand(at)); + __ li(a0, Operand(var->name())); + __ Push(a0); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&uninitialized_this); + EmitStoreToStackLocalOrContextSlot(var, location); + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -3160,22 +3174,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitInitializeThisAfterSuper( - SuperCallReference* super_ref, FeedbackVectorICSlot slot) { - Variable* this_var = super_ref->this_var()->var(); - GetVar(a1, this_var); - __ LoadRoot(at, Heap::kTheHoleValueRootIndex); - Label uninitialized_this; - __ Branch(&uninitialized_this, eq, a1, Operand(at)); - __ li(a0, Operand(this_var->name())); - __ Push(a0); - __ CallRuntime(Runtime::kThrowReferenceError, 1); - __ bind(&uninitialized_this); - - EmitVariableAssignment(this_var, Token::INIT_CONST, slot); -} - - // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { VariableProxy* callee = expr->expression()->AsVariableProxy(); @@ -3395,7 +3393,6 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { RecordJSReturnSite(expr); - EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot()); context()->Plug(v0); } @@ -4763,9 +4760,6 @@ void FullCodeGenerator::EmitCallSuperWithSpread(CallRuntime* expr) { // Restore context register. __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, v0); - - // TODO(mvstanton): with FLAG_vector_stores this needs a slot id. - EmitInitializeThisAfterSuper(super_call_ref); } @@ -4962,7 +4956,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ CountOperation"); diff --git a/src/ppc/full-codegen-ppc.cc b/src/ppc/full-codegen-ppc.cc index fcf21d358..ddb100c19 100644 --- a/src/ppc/full-codegen-ppc.cc +++ b/src/ppc/full-codegen-ppc.cc @@ -1959,7 +1959,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ Assignment"); SetExpressionPosition(expr, INSERT_BREAK); @@ -2676,7 +2676,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackVectorICSlot slot) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); Property* prop = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(prop); @@ -2824,6 +2824,20 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ bind(&const_error); __ CallRuntime(Runtime::kThrowConstAssignError, 0); + } else if (var->is_this() && op == Token::INIT_CONST) { + // Initializing assignment to const {this} needs a write barrier. + DCHECK(var->IsStackAllocated() || var->IsContextSlot()); + Label uninitialized_this; + MemOperand location = VarOperand(var, r4); + __ LoadP(r6, location); + __ CompareRoot(r6, Heap::kTheHoleValueRootIndex); + __ beq(&uninitialized_this); + __ mov(r4, Operand(var->name())); + __ push(r4); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&uninitialized_this); + EmitStoreToStackLocalOrContextSlot(var, location); + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -3166,22 +3180,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitInitializeThisAfterSuper( - SuperCallReference* super_ref, FeedbackVectorICSlot slot) { - Variable* this_var = super_ref->this_var()->var(); - GetVar(r4, this_var); - __ CompareRoot(r4, Heap::kTheHoleValueRootIndex); - Label uninitialized_this; - __ beq(&uninitialized_this); - __ mov(r4, Operand(this_var->name())); - __ push(r4); - __ CallRuntime(Runtime::kThrowReferenceError, 1); - __ bind(&uninitialized_this); - - EmitVariableAssignment(this_var, Token::INIT_CONST, slot); -} - - // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { VariableProxy* callee = expr->expression()->AsVariableProxy(); @@ -3403,7 +3401,6 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { RecordJSReturnSite(expr); - EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot()); context()->Plug(r3); } @@ -4763,9 +4760,6 @@ void FullCodeGenerator::EmitCallSuperWithSpread(CallRuntime* expr) { // Restore context register. __ LoadP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, r3); - - // TODO(mvstanton): with FLAG_vector_stores this needs a slot id. - EmitInitializeThisAfterSuper(super_call_ref); } @@ -4959,7 +4953,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ CountOperation"); diff --git a/src/preparser.h b/src/preparser.h index 921cd875a..8680f88bf 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -947,10 +947,16 @@ class PreParserExpression { ExpressionTypeField::encode(kCallExpression)); } + static PreParserExpression SuperCallReference() { + return PreParserExpression( + TypeField::encode(kExpression) | + ExpressionTypeField::encode(kSuperCallReference)); + } + static PreParserExpression NoTemplateTag() { - return PreParserExpression(TypeField::encode(kExpression) | - ExpressionTypeField::encode( - kNoTemplateTagExpression)); + return PreParserExpression( + TypeField::encode(kExpression) | + ExpressionTypeField::encode(kNoTemplateTagExpression)); } bool IsIdentifier() const { @@ -997,6 +1003,11 @@ class PreParserExpression { ExpressionTypeField::decode(code_) == kCallExpression; } + bool IsSuperCallReference() const { + return TypeField::decode(code_) == kExpression && + ExpressionTypeField::decode(code_) == kSuperCallReference; + } + bool IsValidReferenceExpression() const { return IsIdentifier() || IsProperty(); } @@ -1045,6 +1056,7 @@ class PreParserExpression { kThisPropertyExpression, kPropertyExpression, kCallExpression, + kSuperCallReference, kNoTemplateTagExpression }; @@ -1528,7 +1540,7 @@ class PreParserTraits { static PreParserExpression SuperCallReference(Scope* scope, PreParserFactory* factory, int pos) { - return PreParserExpression::Default(); + return PreParserExpression::SuperCallReference(); } static PreParserExpression NewTargetExpression(Scope* scope, @@ -3184,12 +3196,22 @@ ParserBase::ParseLeftHandSideExpression( // they are actually direct calls to eval is determined at run time. this->CheckPossibleEvalCall(result, scope_); + bool is_super_call = result->IsSuperCallReference(); if (spread_pos.IsValid()) { args = Traits::PrepareSpreadArguments(args); result = Traits::SpreadCall(result, args, pos); } else { result = factory()->NewCall(result, args, pos); } + + // Explicit calls to the super constructor using super() perform an + // implicit binding assignment to the 'this' variable. + if (is_super_call) { + ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos); + result = factory()->NewAssignment(Token::INIT_CONST, this_expr, + result, pos); + } + if (fni_ != NULL) fni_->RemoveLastFunction(); break; } @@ -3462,10 +3484,15 @@ ParserBase::ParseStrongSuperCallExpression( function_state_->set_super_location(super_loc); if (spread_pos.IsValid()) { args = Traits::PrepareSpreadArguments(args); - return Traits::SpreadCall(expr, args, pos); + expr = Traits::SpreadCall(expr, args, pos); } else { - return factory()->NewCall(expr, args, pos); + expr = factory()->NewCall(expr, args, pos); } + + // Explicit calls to the super constructor using super() perform an implicit + // binding assignment to the 'this' variable. + ExpressionT this_expr = this->ThisExpression(scope_, factory(), pos); + return factory()->NewAssignment(Token::INIT_CONST, this_expr, expr, pos); } diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index 8f2da733f..a84a8e6d9 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -1952,7 +1952,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ Assignment"); SetExpressionPosition(expr, INSERT_BREAK); @@ -2578,7 +2578,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackVectorICSlot slot) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); Property* prop = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(prop); @@ -2720,6 +2720,19 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ bind(&const_error); __ CallRuntime(Runtime::kThrowConstAssignError, 0); + } else if (var->is_this() && op == Token::INIT_CONST) { + // Initializing assignment to const {this} needs a write barrier. + DCHECK(var->IsStackAllocated() || var->IsContextSlot()); + Label uninitialized_this; + MemOperand location = VarOperand(var, rcx); + __ movp(rdx, location); + __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); + __ j(equal, &uninitialized_this); + __ Push(var->name()); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&uninitialized_this); + EmitStoreToStackLocalOrContextSlot(var, location); + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -3061,21 +3074,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitInitializeThisAfterSuper( - SuperCallReference* super_ref, FeedbackVectorICSlot slot) { - Variable* this_var = super_ref->this_var()->var(); - GetVar(rcx, this_var); - __ CompareRoot(rcx, Heap::kTheHoleValueRootIndex); - Label uninitialized_this; - __ j(equal, &uninitialized_this); - __ Push(this_var->name()); - __ CallRuntime(Runtime::kThrowReferenceError, 1); - __ bind(&uninitialized_this); - - EmitVariableAssignment(this_var, Token::INIT_CONST, slot); -} - - // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { VariableProxy* callee = expr->expression()->AsVariableProxy(); @@ -3290,7 +3288,6 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { RecordJSReturnSite(expr); - EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot()); context()->Plug(rax); } @@ -4692,9 +4689,6 @@ void FullCodeGenerator::EmitCallSuperWithSpread(CallRuntime* expr) { // Restore context register. __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, rax); - - // TODO(mvstanton): with FLAG_vector_stores this needs a slot id. - EmitInitializeThisAfterSuper(super_call_ref); } @@ -4894,7 +4888,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ CountOperation"); diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index d5b53af32..8b84d9404 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc @@ -1918,7 +1918,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void FullCodeGenerator::VisitAssignment(Assignment* expr) { - DCHECK(expr->target()->IsValidReferenceExpression()); + DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ Assignment"); SetExpressionPosition(expr, INSERT_BREAK); @@ -2575,7 +2575,7 @@ void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) { void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackVectorICSlot slot) { - DCHECK(expr->IsValidReferenceExpression()); + DCHECK(expr->IsValidReferenceExpressionOrThis()); Property* prop = expr->AsProperty(); LhsKind assign_type = Property::GetAssignType(prop); @@ -2717,6 +2717,19 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, __ bind(&const_error); __ CallRuntime(Runtime::kThrowConstAssignError, 0); + } else if (var->is_this() && op == Token::INIT_CONST) { + // Initializing assignment to const {this} needs a write barrier. + DCHECK(var->IsStackAllocated() || var->IsContextSlot()); + Label uninitialized_this; + MemOperand location = VarOperand(var, ecx); + __ mov(edx, location); + __ cmp(edx, isolate()->factory()->the_hole_value()); + __ j(equal, &uninitialized_this); + __ push(Immediate(var->name())); + __ CallRuntime(Runtime::kThrowReferenceError, 1); + __ bind(&uninitialized_this); + EmitStoreToStackLocalOrContextSlot(var, location); + } else if (!var->is_const_mode() || op == Token::INIT_CONST) { if (var->IsLookupSlot()) { // Assignment to var. @@ -3059,22 +3072,6 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { } -void FullCodeGenerator::EmitInitializeThisAfterSuper( - SuperCallReference* super_call_ref, FeedbackVectorICSlot slot) { - Variable* this_var = super_call_ref->this_var()->var(); - GetVar(ecx, this_var); - __ cmp(ecx, isolate()->factory()->the_hole_value()); - - Label uninitialized_this; - __ j(equal, &uninitialized_this); - __ push(Immediate(this_var->name())); - __ CallRuntime(Runtime::kThrowReferenceError, 1); - __ bind(&uninitialized_this); - - EmitVariableAssignment(this_var, Token::INIT_CONST, slot); -} - - // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls. void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) { VariableProxy* callee = expr->expression()->AsVariableProxy(); @@ -3290,7 +3287,6 @@ void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) { RecordJSReturnSite(expr); - EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot()); context()->Plug(eax); } @@ -4665,9 +4661,6 @@ void FullCodeGenerator::EmitCallSuperWithSpread(CallRuntime* expr) { // Restore context register. __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); context()->DropAndPlug(1, eax); - - // TODO(mvstanton): with FLAG_vector_stores this needs a slot id. - EmitInitializeThisAfterSuper(super_call_ref); } @@ -4866,7 +4859,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { - DCHECK(expr->expression()->IsValidReferenceExpression()); + DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); Comment cmnt(masm_, "[ CountOperation"); diff --git a/test/mjsunit/harmony/super.js b/test/mjsunit/harmony/super.js index 270c159e8..ab572b056 100644 --- a/test/mjsunit/harmony/super.js +++ b/test/mjsunit/harmony/super.js @@ -1979,7 +1979,8 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); class Derived extends Base { constructor() { - super(); + let r = super(); + assertEquals(this, r); derivedCalled++; } } @@ -1995,7 +1996,8 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); class DerivedDerived extends Derived { constructor() { - super(); + let r = super(); + assertEquals(this, r); derivedDerivedCalled++; } } @@ -2015,7 +2017,8 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); } class Derived2 extends Base2 { constructor(v1, v2) { - super(v1); + let r = super(v1); + assertEquals(this, r); this.fromDerived = v2; } } @@ -2128,7 +2131,8 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); } class Derived extends Base { constructor(x) { - eval('super(x)'); + let r = eval('super(x)'); + assertEquals(this, r); } } let d = new Derived(42); @@ -2145,7 +2149,8 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); } class Derived extends Base { constructor(x) { - (() => super(x))(); + let r = (() => super(x))(); + assertEquals(this, r); } } let d = new Derived(42); @@ -2231,7 +2236,8 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); } class Derived extends Base { constructor(x) { - eval('super(...[x])'); + let r = eval('super(...[x])'); + assertEquals(this, r); } } let d = new Derived(42); @@ -2248,7 +2254,8 @@ TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); } class Derived extends Base { constructor(x) { - (() => super(...[x]))(); + let r = (() => super(...[x]))(); + assertEquals(this, r); } } let d = new Derived(42); -- 2.34.1