void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- DCHECK(expr->target()->IsValidReferenceExpression());
+ DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ Assignment");
SetExpressionPosition(expr, INSERT_BREAK);
void FullCodeGenerator::EmitAssignment(Expression* expr,
FeedbackVectorICSlot slot) {
- DCHECK(expr->IsValidReferenceExpression());
+ DCHECK(expr->IsValidReferenceExpressionOrThis());
Property* prop = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(prop);
__ 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.
}
-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();
RecordJSReturnSite(expr);
- EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot());
context()->Plug(r0);
}
// 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);
}
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- DCHECK(expr->expression()->IsValidReferenceExpression());
+ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ CountOperation");
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- DCHECK(expr->target()->IsValidReferenceExpression());
+ DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ Assignment");
SetExpressionPosition(expr, INSERT_BREAK);
void FullCodeGenerator::EmitAssignment(Expression* expr,
FeedbackVectorICSlot slot) {
- DCHECK(expr->IsValidReferenceExpression());
+ DCHECK(expr->IsValidReferenceExpressionOrThis());
Property* prop = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(prop);
__ 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.
}
-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();
RecordJSReturnSite(expr);
- EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot());
context()->Plug(x0);
}
// 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);
}
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- DCHECK(expr->expression()->IsValidReferenceExpression());
+ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ CountOperation");
}
+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),
kTest
};
+ // True iff the expression is a valid reference expression.
virtual bool IsValidReferenceExpression() const { return false; }
// Helpers for ToBoolean conversion.
// 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; }
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();
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();
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);
}
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();
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());
- }
}
FeedbackVectorICSlot slot = FeedbackVectorICSlot::Invalid());
void EmitLoadSuperConstructor(SuperCallReference* super_call_ref);
- void EmitInitializeThisAfterSuper(
- SuperCallReference* super_call_ref,
- FeedbackVectorICSlot slot = FeedbackVectorICSlot::Invalid());
void CallIC(Handle<Code> code,
TypeFeedbackId id = TypeFeedbackId::None());
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- DCHECK(expr->target()->IsValidReferenceExpression());
+ DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ Assignment");
SetExpressionPosition(expr, INSERT_BREAK);
void FullCodeGenerator::EmitAssignment(Expression* expr,
FeedbackVectorICSlot slot) {
- DCHECK(expr->IsValidReferenceExpression());
+ DCHECK(expr->IsValidReferenceExpressionOrThis());
Property* prop = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(prop);
__ 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.
}
-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();
RecordJSReturnSite(expr);
- EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot());
context()->Plug(eax);
}
// 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);
}
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- DCHECK(expr->expression()->IsValidReferenceExpression());
+ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ CountOperation");
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- DCHECK(expr->target()->IsValidReferenceExpression());
+ DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ Assignment");
SetExpressionPosition(expr, INSERT_BREAK);
void FullCodeGenerator::EmitAssignment(Expression* expr,
FeedbackVectorICSlot slot) {
- DCHECK(expr->IsValidReferenceExpression());
+ DCHECK(expr->IsValidReferenceExpressionOrThis());
Property* prop = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(prop);
__ 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.
}
-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();
RecordJSReturnSite(expr);
- EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot());
context()->Plug(v0);
}
// 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);
}
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- DCHECK(expr->expression()->IsValidReferenceExpression());
+ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ CountOperation");
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- DCHECK(expr->target()->IsValidReferenceExpression());
+ DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ Assignment");
SetExpressionPosition(expr, INSERT_BREAK);
void FullCodeGenerator::EmitAssignment(Expression* expr,
FeedbackVectorICSlot slot) {
- DCHECK(expr->IsValidReferenceExpression());
+ DCHECK(expr->IsValidReferenceExpressionOrThis());
Property* prop = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(prop);
__ 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.
}
-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();
RecordJSReturnSite(expr);
- EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot());
context()->Plug(v0);
}
// 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);
}
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- DCHECK(expr->expression()->IsValidReferenceExpression());
+ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ CountOperation");
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- DCHECK(expr->target()->IsValidReferenceExpression());
+ DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ Assignment");
SetExpressionPosition(expr, INSERT_BREAK);
void FullCodeGenerator::EmitAssignment(Expression* expr,
FeedbackVectorICSlot slot) {
- DCHECK(expr->IsValidReferenceExpression());
+ DCHECK(expr->IsValidReferenceExpressionOrThis());
Property* prop = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(prop);
__ 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.
}
-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();
RecordJSReturnSite(expr);
- EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot());
context()->Plug(r3);
}
// 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);
}
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- DCHECK(expr->expression()->IsValidReferenceExpression());
+ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ CountOperation");
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 {
ExpressionTypeField::decode(code_) == kCallExpression;
}
+ bool IsSuperCallReference() const {
+ return TypeField::decode(code_) == kExpression &&
+ ExpressionTypeField::decode(code_) == kSuperCallReference;
+ }
+
bool IsValidReferenceExpression() const {
return IsIdentifier() || IsProperty();
}
kThisPropertyExpression,
kPropertyExpression,
kCallExpression,
+ kSuperCallReference,
kNoTemplateTagExpression
};
static PreParserExpression SuperCallReference(Scope* scope,
PreParserFactory* factory,
int pos) {
- return PreParserExpression::Default();
+ return PreParserExpression::SuperCallReference();
}
static PreParserExpression NewTargetExpression(Scope* scope,
// 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;
}
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);
}
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- DCHECK(expr->target()->IsValidReferenceExpression());
+ DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ Assignment");
SetExpressionPosition(expr, INSERT_BREAK);
void FullCodeGenerator::EmitAssignment(Expression* expr,
FeedbackVectorICSlot slot) {
- DCHECK(expr->IsValidReferenceExpression());
+ DCHECK(expr->IsValidReferenceExpressionOrThis());
Property* prop = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(prop);
__ 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.
}
-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();
RecordJSReturnSite(expr);
- EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot());
context()->Plug(rax);
}
// 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);
}
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- DCHECK(expr->expression()->IsValidReferenceExpression());
+ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ CountOperation");
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- DCHECK(expr->target()->IsValidReferenceExpression());
+ DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ Assignment");
SetExpressionPosition(expr, INSERT_BREAK);
void FullCodeGenerator::EmitAssignment(Expression* expr,
FeedbackVectorICSlot slot) {
- DCHECK(expr->IsValidReferenceExpression());
+ DCHECK(expr->IsValidReferenceExpressionOrThis());
Property* prop = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(prop);
__ 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.
}
-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();
RecordJSReturnSite(expr);
- EmitInitializeThisAfterSuper(super_call_ref, expr->CallFeedbackICSlot());
context()->Plug(eax);
}
// 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);
}
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- DCHECK(expr->expression()->IsValidReferenceExpression());
+ DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
Comment cmnt(masm_, "[ CountOperation");
class Derived extends Base {
constructor() {
- super();
+ let r = super();
+ assertEquals(this, r);
derivedCalled++;
}
}
class DerivedDerived extends Derived {
constructor() {
- super();
+ let r = super();
+ assertEquals(this, r);
derivedDerivedCalled++;
}
}
}
class Derived2 extends Base2 {
constructor(v1, v2) {
- super(v1);
+ let r = super(v1);
+ assertEquals(this, r);
this.fromDerived = v2;
}
}
}
class Derived extends Base {
constructor(x) {
- eval('super(x)');
+ let r = eval('super(x)');
+ assertEquals(this, r);
}
}
let d = new Derived(42);
}
class Derived extends Base {
constructor(x) {
- (() => super(x))();
+ let r = (() => super(x))();
+ assertEquals(this, r);
}
}
let d = new Derived(42);
}
class Derived extends Base {
constructor(x) {
- eval('super(...[x])');
+ let r = eval('super(...[x])');
+ assertEquals(this, r);
}
}
let d = new Derived(42);
}
class Derived extends Base {
constructor(x) {
- (() => super(...[x]))();
+ let r = (() => super(...[x]))();
+ assertEquals(this, r);
}
}
let d = new Derived(42);