Commit 231c8ac0 authored by adamk's avatar adamk Committed by Commit bot

[full-codegen] Eliminate unnecessary hole checks for stores

Loads already used source position elimination to avoid unnecessary hole checks,
but for reasons unknown stores did not. This CL corrects that, making full-codegen's
hole elimination equivalent to ignition's.

Also introduced a HoleCheckMode enum class to avoid more bool flags and updated
VariableProxy and BytecodeGenerator appropriately.

Review-Url: https://codereview.chromium.org/2441543005
Cr-Commit-Position: refs/heads/master@{#40522}
parent 8e742617
...@@ -165,9 +165,10 @@ VariableProxy::VariableProxy(Variable* var, int start_position, ...@@ -165,9 +165,10 @@ VariableProxy::VariableProxy(Variable* var, int start_position,
end_position_(end_position), end_position_(end_position),
raw_name_(var->raw_name()), raw_name_(var->raw_name()),
next_unresolved_(nullptr) { next_unresolved_(nullptr) {
bit_field_ |= bit_field_ |= IsThisField::encode(var->is_this()) |
IsThisField::encode(var->is_this()) | IsAssignedField::encode(false) | IsAssignedField::encode(false) |
IsResolvedField::encode(false) | NeedsHoleCheckField::encode(false); IsResolvedField::encode(false) |
HoleCheckModeField::encode(HoleCheckMode::kElided);
BindTo(var); BindTo(var);
} }
...@@ -181,7 +182,7 @@ VariableProxy::VariableProxy(const AstRawString* name, ...@@ -181,7 +182,7 @@ VariableProxy::VariableProxy(const AstRawString* name,
bit_field_ |= IsThisField::encode(variable_kind == THIS_VARIABLE) | bit_field_ |= IsThisField::encode(variable_kind == THIS_VARIABLE) |
IsAssignedField::encode(false) | IsAssignedField::encode(false) |
IsResolvedField::encode(false) | IsResolvedField::encode(false) |
NeedsHoleCheckField::encode(false); HoleCheckModeField::encode(HoleCheckMode::kElided);
} }
VariableProxy::VariableProxy(const VariableProxy* copy_from) VariableProxy::VariableProxy(const VariableProxy* copy_from)
......
...@@ -1671,11 +1671,12 @@ class VariableProxy final : public Expression { ...@@ -1671,11 +1671,12 @@ class VariableProxy final : public Expression {
bit_field_ = IsNewTargetField::update(bit_field_, true); bit_field_ = IsNewTargetField::update(bit_field_, true);
} }
bool needs_hole_check() const { HoleCheckMode hole_check_mode() const {
return NeedsHoleCheckField::decode(bit_field_); return HoleCheckModeField::decode(bit_field_);
} }
void set_needs_hole_check() { void set_needs_hole_check() {
bit_field_ = NeedsHoleCheckField::update(bit_field_, true); bit_field_ =
HoleCheckModeField::update(bit_field_, HoleCheckMode::kRequired);
} }
int end_position() const { return end_position_; } int end_position() const { return end_position_; }
...@@ -1713,8 +1714,8 @@ class VariableProxy final : public Expression { ...@@ -1713,8 +1714,8 @@ class VariableProxy final : public Expression {
class IsAssignedField : public BitField<bool, IsThisField::kNext, 1> {}; class IsAssignedField : public BitField<bool, IsThisField::kNext, 1> {};
class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {}; class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {};
class IsNewTargetField : public BitField<bool, IsResolvedField::kNext, 1> {}; class IsNewTargetField : public BitField<bool, IsResolvedField::kNext, 1> {};
class NeedsHoleCheckField class HoleCheckModeField
: public BitField<bool, IsNewTargetField::kNext, 1> {}; : public BitField<HoleCheckMode, IsNewTargetField::kNext, 1> {};
// Position is stored in the AstNode superclass, but VariableProxy needs to // Position is stored in the AstNode superclass, but VariableProxy needs to
// know its end position too (for error messages). It cannot be inferred from // know its end position too (for error messages). It cannot be inferred from
......
...@@ -1287,7 +1287,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ...@@ -1287,7 +1287,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable"); : "[ Stack variable");
if (proxy->needs_hole_check()) { if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
// Throw a reference error when using an uninitialized let/const // Throw a reference error when using an uninitialized let/const
// binding in harmony mode. // binding in harmony mode.
Label done; Label done;
...@@ -1730,12 +1730,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1730,12 +1730,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), VariableProxy* proxy = expr->target()->AsVariableProxy();
expr->op(), expr->AssignmentSlot()); EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
context()->Plug(r0); context()->Plug(r0);
break; break;
}
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
break; break;
...@@ -2017,9 +2019,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, ...@@ -2017,9 +2019,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr,
switch (assign_type) { switch (assign_type) {
case VARIABLE: { case VARIABLE: {
Variable* var = expr->AsVariableProxy()->var(); VariableProxy* proxy = expr->AsVariableProxy();
EffectContext context(this); EffectContext context(this);
EmitVariableAssignment(var, Token::ASSIGN, slot); EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
proxy->hole_check_mode());
break; break;
} }
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
...@@ -2094,9 +2097,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( ...@@ -2094,9 +2097,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
} }
} }
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorSlot slot) { FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode) {
if (var->IsUnallocated()) { if (var->IsUnallocated()) {
// Global var, const, or let. // Global var, const, or let.
__ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); __ LoadGlobalObject(StoreDescriptor::ReceiverRegister());
...@@ -2107,7 +2110,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, ...@@ -2107,7 +2110,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
MemOperand location = VarOperand(var, r1); MemOperand location = VarOperand(var, r1);
// Perform an initialization check for lexically declared variables. // Perform an initialization check for lexically declared variables.
if (var->binding_needs_init()) { if (hole_check_mode == HoleCheckMode::kRequired) {
Label assign; Label assign;
__ ldr(r3, location); __ ldr(r3, location);
__ CompareRoot(r3, Heap::kTheHoleValueRootIndex); __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
...@@ -3188,11 +3191,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3188,11 +3191,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Store the value returned in r0. // Store the value returned in r0.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (expr->is_postfix()) { if (expr->is_postfix()) {
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context.Plug(r0); context.Plug(r0);
...@@ -3203,13 +3207,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3203,13 +3207,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
context()->PlugTOS(); context()->PlugTOS();
} }
} else { } else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context()->Plug(r0); context()->Plug(r0);
} }
break; break;
}
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
PopOperand(StoreDescriptor::ReceiverRegister()); PopOperand(StoreDescriptor::ReceiverRegister());
CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value());
......
...@@ -1275,7 +1275,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ...@@ -1275,7 +1275,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
Comment cmnt(masm_, var->IsContextSlot() Comment cmnt(masm_, var->IsContextSlot()
? "Context variable" ? "Context variable"
: "Stack variable"); : "Stack variable");
if (proxy->needs_hole_check()) { if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
// Throw a reference error when using an uninitialized let/const // Throw a reference error when using an uninitialized let/const
// binding in harmony mode. // binding in harmony mode.
Label done; Label done;
...@@ -1710,12 +1710,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1710,12 +1710,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), VariableProxy* proxy = expr->target()->AsVariableProxy();
expr->op(), expr->AssignmentSlot()); EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
context()->Plug(x0); context()->Plug(x0);
break; break;
}
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
break; break;
...@@ -1908,9 +1910,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, ...@@ -1908,9 +1910,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr,
switch (assign_type) { switch (assign_type) {
case VARIABLE: { case VARIABLE: {
Variable* var = expr->AsVariableProxy()->var(); VariableProxy* proxy = expr->AsVariableProxy();
EffectContext context(this); EffectContext context(this);
EmitVariableAssignment(var, Token::ASSIGN, slot); EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
proxy->hole_check_mode());
break; break;
} }
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
...@@ -1987,9 +1990,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( ...@@ -1987,9 +1990,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
} }
} }
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorSlot slot) { FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode) {
ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment"); ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment");
if (var->IsUnallocated()) { if (var->IsUnallocated()) {
// Global var, const, or let. // Global var, const, or let.
...@@ -3106,11 +3109,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3106,11 +3109,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Store the value returned in x0. // Store the value returned in x0.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (expr->is_postfix()) { if (expr->is_postfix()) {
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context.Plug(x0); context.Plug(x0);
...@@ -3121,13 +3125,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3121,13 +3125,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
context()->PlugTOS(); context()->PlugTOS();
} }
} else { } else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context()->Plug(x0); context()->Plug(x0);
} }
break; break;
}
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
PopOperand(StoreDescriptor::ReceiverRegister()); PopOperand(StoreDescriptor::ReceiverRegister());
CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value());
......
...@@ -1582,7 +1582,7 @@ void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) { ...@@ -1582,7 +1582,7 @@ void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) {
if (lit->class_variable_proxy() != nullptr) { if (lit->class_variable_proxy() != nullptr) {
EmitVariableAssignment(lit->class_variable_proxy()->var(), Token::INIT, EmitVariableAssignment(lit->class_variable_proxy()->var(), Token::INIT,
lit->ProxySlot()); lit->ProxySlot(), HoleCheckMode::kElided);
} }
context()->Plug(result_register()); context()->Plug(result_register());
......
...@@ -572,7 +572,8 @@ class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> { ...@@ -572,7 +572,8 @@ class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> {
// Complete a variable assignment. The right-hand-side value is expected // Complete a variable assignment. The right-hand-side value is expected
// in the accumulator. // in the accumulator.
void EmitVariableAssignment(Variable* var, Token::Value op, void EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorSlot slot); FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode);
// Helper functions to EmitVariableAssignment // Helper functions to EmitVariableAssignment
void EmitStoreToStackLocalOrContextSlot(Variable* var, void EmitStoreToStackLocalOrContextSlot(Variable* var,
......
...@@ -1210,7 +1210,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ...@@ -1210,7 +1210,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable"); : "[ Stack variable");
if (proxy->needs_hole_check()) { if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
// Throw a reference error when using an uninitialized let/const // Throw a reference error when using an uninitialized let/const
// binding in harmony mode. // binding in harmony mode.
Label done; Label done;
...@@ -1643,12 +1643,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1643,12 +1643,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), VariableProxy* proxy = expr->target()->AsVariableProxy();
expr->op(), expr->AssignmentSlot()); EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
context()->Plug(eax); context()->Plug(eax);
break; break;
}
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
break; break;
...@@ -1927,9 +1929,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, ...@@ -1927,9 +1929,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr,
switch (assign_type) { switch (assign_type) {
case VARIABLE: { case VARIABLE: {
Variable* var = expr->AsVariableProxy()->var(); VariableProxy* proxy = expr->AsVariableProxy();
EffectContext context(this); EffectContext context(this);
EmitVariableAssignment(var, Token::ASSIGN, slot); EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
proxy->hole_check_mode());
break; break;
} }
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
...@@ -2002,9 +2005,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( ...@@ -2002,9 +2005,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
} }
} }
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorSlot slot) { FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode) {
if (var->IsUnallocated()) { if (var->IsUnallocated()) {
// Global var, const, or let. // Global var, const, or let.
__ mov(StoreDescriptor::ReceiverRegister(), NativeContextOperand()); __ mov(StoreDescriptor::ReceiverRegister(), NativeContextOperand());
...@@ -2018,7 +2021,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, ...@@ -2018,7 +2021,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
MemOperand location = VarOperand(var, ecx); MemOperand location = VarOperand(var, ecx);
// Perform an initialization check for lexically declared variables. // Perform an initialization check for lexically declared variables.
if (var->binding_needs_init()) { if (hole_check_mode == HoleCheckMode::kRequired) {
Label assign; Label assign;
__ mov(edx, location); __ mov(edx, location);
__ cmp(edx, isolate()->factory()->the_hole_value()); __ cmp(edx, isolate()->factory()->the_hole_value());
...@@ -3084,12 +3087,13 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3084,12 +3087,13 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Store the value returned in eax. // Store the value returned in eax.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (expr->is_postfix()) { if (expr->is_postfix()) {
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context.Plug(eax); context.Plug(eax);
...@@ -3101,13 +3105,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3101,13 +3105,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
} }
} else { } else {
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context()->Plug(eax); context()->Plug(eax);
} }
break; break;
}
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
PopOperand(StoreDescriptor::ReceiverRegister()); PopOperand(StoreDescriptor::ReceiverRegister());
CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value());
......
...@@ -1287,7 +1287,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ...@@ -1287,7 +1287,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable"); : "[ Stack variable");
if (proxy->needs_hole_check()) { if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
// Throw a reference error when using an uninitialized let/const // Throw a reference error when using an uninitialized let/const
// binding in harmony mode. // binding in harmony mode.
Label done; Label done;
...@@ -1731,12 +1731,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1731,12 +1731,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), VariableProxy* proxy = expr->target()->AsVariableProxy();
expr->op(), expr->AssignmentSlot()); EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
context()->Plug(v0); context()->Plug(v0);
break; break;
}
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
break; break;
...@@ -2025,9 +2027,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, ...@@ -2025,9 +2027,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr,
switch (assign_type) { switch (assign_type) {
case VARIABLE: { case VARIABLE: {
Variable* var = expr->AsVariableProxy()->var(); VariableProxy* proxy = expr->AsVariableProxy();
EffectContext context(this); EffectContext context(this);
EmitVariableAssignment(var, Token::ASSIGN, slot); EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
proxy->hole_check_mode());
break; break;
} }
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
...@@ -2102,9 +2105,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( ...@@ -2102,9 +2105,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
} }
} }
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorSlot slot) { FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode) {
if (var->IsUnallocated()) { if (var->IsUnallocated()) {
// Global var, const, or let. // Global var, const, or let.
__ mov(StoreDescriptor::ValueRegister(), result_register()); __ mov(StoreDescriptor::ValueRegister(), result_register());
...@@ -2116,7 +2119,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, ...@@ -2116,7 +2119,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
MemOperand location = VarOperand(var, a1); MemOperand location = VarOperand(var, a1);
// Perform an initialization check for lexically declared variables. // Perform an initialization check for lexically declared variables.
if (var->binding_needs_init()) { if (hole_check_mode == HoleCheckMode::kRequired) {
Label assign; Label assign;
__ lw(a3, location); __ lw(a3, location);
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex); __ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
...@@ -3195,11 +3198,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3195,11 +3198,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Store the value returned in v0. // Store the value returned in v0.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (expr->is_postfix()) { if (expr->is_postfix()) {
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context.Plug(v0); context.Plug(v0);
...@@ -3210,13 +3214,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3210,13 +3214,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
context()->PlugTOS(); context()->PlugTOS();
} }
} else { } else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context()->Plug(v0); context()->Plug(v0);
} }
break; break;
}
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
__ mov(StoreDescriptor::ValueRegister(), result_register()); __ mov(StoreDescriptor::ValueRegister(), result_register());
PopOperand(StoreDescriptor::ReceiverRegister()); PopOperand(StoreDescriptor::ReceiverRegister());
......
...@@ -1288,7 +1288,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ...@@ -1288,7 +1288,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable"); : "[ Stack variable");
if (proxy->needs_hole_check()) { if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
// Throw a reference error when using an uninitialized let/const // Throw a reference error when using an uninitialized let/const
// binding in harmony mode. // binding in harmony mode.
Label done; Label done;
...@@ -1732,12 +1732,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1732,12 +1732,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), VariableProxy* proxy = expr->target()->AsVariableProxy();
expr->op(), expr->AssignmentSlot()); EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
context()->Plug(v0); context()->Plug(v0);
break; break;
}
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
break; break;
...@@ -2025,9 +2027,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, ...@@ -2025,9 +2027,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr,
switch (assign_type) { switch (assign_type) {
case VARIABLE: { case VARIABLE: {
Variable* var = expr->AsVariableProxy()->var(); VariableProxy* proxy = expr->AsVariableProxy();
EffectContext context(this); EffectContext context(this);
EmitVariableAssignment(var, Token::ASSIGN, slot); EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
proxy->hole_check_mode());
break; break;
} }
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
...@@ -2102,9 +2105,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( ...@@ -2102,9 +2105,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
} }
} }
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorSlot slot) { FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode) {
if (var->IsUnallocated()) { if (var->IsUnallocated()) {
// Global var, const, or let. // Global var, const, or let.
__ mov(StoreDescriptor::ValueRegister(), result_register()); __ mov(StoreDescriptor::ValueRegister(), result_register());
...@@ -2116,7 +2119,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, ...@@ -2116,7 +2119,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
MemOperand location = VarOperand(var, a1); MemOperand location = VarOperand(var, a1);
// Perform an initialization check for lexically declared variables. // Perform an initialization check for lexically declared variables.
if (var->binding_needs_init()) { if (hole_check_mode == HoleCheckMode::kRequired) {
Label assign; Label assign;
__ ld(a3, location); __ ld(a3, location);
__ LoadRoot(a4, Heap::kTheHoleValueRootIndex); __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
...@@ -3195,11 +3198,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3195,11 +3198,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Store the value returned in v0. // Store the value returned in v0.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (expr->is_postfix()) { if (expr->is_postfix()) {
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context.Plug(v0); context.Plug(v0);
...@@ -3210,13 +3214,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3210,13 +3214,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
context()->PlugTOS(); context()->PlugTOS();
} }
} else { } else {
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context()->Plug(v0); context()->Plug(v0);
} }
break; break;
}
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
__ mov(StoreDescriptor::ValueRegister(), result_register()); __ mov(StoreDescriptor::ValueRegister(), result_register());
PopOperand(StoreDescriptor::ReceiverRegister()); PopOperand(StoreDescriptor::ReceiverRegister());
......
...@@ -1239,7 +1239,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ...@@ -1239,7 +1239,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode); DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot" Comment cmnt(masm_, var->IsContextSlot() ? "[ Context slot"
: "[ Stack slot"); : "[ Stack slot");
if (proxy->needs_hole_check()) { if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
// Throw a reference error when using an uninitialized let/const // Throw a reference error when using an uninitialized let/const
// binding in harmony mode. // binding in harmony mode.
DCHECK(IsLexicalVariableMode(var->mode())); DCHECK(IsLexicalVariableMode(var->mode()));
...@@ -1670,12 +1670,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) { ...@@ -1670,12 +1670,14 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// Store the value. // Store the value.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), VariableProxy* proxy = expr->target()->AsVariableProxy();
expr->op(), expr->AssignmentSlot()); EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER); PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
context()->Plug(rax); context()->Plug(rax);
break; break;
}
case NAMED_PROPERTY: case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr); EmitNamedPropertyAssignment(expr);
break; break;
...@@ -1919,9 +1921,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr, ...@@ -1919,9 +1921,10 @@ void FullCodeGenerator::EmitAssignment(Expression* expr,
switch (assign_type) { switch (assign_type) {
case VARIABLE: { case VARIABLE: {
Variable* var = expr->AsVariableProxy()->var(); VariableProxy* proxy = expr->AsVariableProxy();
EffectContext context(this); EffectContext context(this);
EmitVariableAssignment(var, Token::ASSIGN, slot); EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
proxy->hole_check_mode());
break; break;
} }
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
...@@ -1994,9 +1997,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( ...@@ -1994,9 +1997,9 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
} }
} }
void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
FeedbackVectorSlot slot) { FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode) {
if (var->IsUnallocated()) { if (var->IsUnallocated()) {
// Global var, const, or let. // Global var, const, or let.
__ LoadGlobalObject(StoreDescriptor::ReceiverRegister()); __ LoadGlobalObject(StoreDescriptor::ReceiverRegister());
...@@ -2007,7 +2010,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, ...@@ -2007,7 +2010,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
MemOperand location = VarOperand(var, rcx); MemOperand location = VarOperand(var, rcx);
// Perform an initialization check for lexically declared variables. // Perform an initialization check for lexically declared variables.
if (var->binding_needs_init()) { if (hole_check_mode == HoleCheckMode::kRequired) {
Label assign; Label assign;
__ movp(rdx, location); __ movp(rdx, location);
__ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex);
...@@ -3073,12 +3076,13 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3073,12 +3076,13 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Store the value returned in rax. // Store the value returned in rax.
switch (assign_type) { switch (assign_type) {
case VARIABLE: case VARIABLE: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (expr->is_postfix()) { if (expr->is_postfix()) {
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
{ EffectContext context(this); { EffectContext context(this);
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context.Plug(rax); context.Plug(rax);
...@@ -3090,13 +3094,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { ...@@ -3090,13 +3094,14 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
} }
} else { } else {
// Perform the assignment as if via '='. // Perform the assignment as if via '='.
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
Token::ASSIGN, expr->CountSlot()); proxy->hole_check_mode());
PrepareForBailoutForId(expr->AssignmentId(), PrepareForBailoutForId(expr->AssignmentId(),
BailoutState::TOS_REGISTER); BailoutState::TOS_REGISTER);
context()->Plug(rax); context()->Plug(rax);
} }
break; break;
}
case NAMED_PROPERTY: { case NAMED_PROPERTY: {
PopOperand(StoreDescriptor::ReceiverRegister()); PopOperand(StoreDescriptor::ReceiverRegister());
CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value()); CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value());
......
...@@ -1049,6 +1049,8 @@ enum VariableLocation : uint8_t { ...@@ -1049,6 +1049,8 @@ enum VariableLocation : uint8_t {
// immediately initialized upon creation (kCreatedInitialized). // immediately initialized upon creation (kCreatedInitialized).
enum InitializationFlag : uint8_t { kNeedsInitialization, kCreatedInitialized }; enum InitializationFlag : uint8_t { kNeedsInitialization, kCreatedInitialized };
enum class HoleCheckMode { kRequired, kElided };
enum MaybeAssignedFlag : uint8_t { kNotAssigned, kMaybeAssigned }; enum MaybeAssignedFlag : uint8_t { kNotAssigned, kMaybeAssigned };
// Serialized in PreparseData, so numeric values should not be changed. // Serialized in PreparseData, so numeric values should not be changed.
......
This diff is collapsed.
...@@ -95,13 +95,15 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -95,13 +95,15 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitPropertyLoadForAccumulator(Register obj, Property* expr); void VisitPropertyLoadForAccumulator(Register obj, Property* expr);
void BuildVariableLoad(Variable* variable, FeedbackVectorSlot slot, void BuildVariableLoad(Variable* variable, FeedbackVectorSlot slot,
bool needs_hole_check, HoleCheckMode hole_check_mode,
TypeofMode typeof_mode = NOT_INSIDE_TYPEOF); TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
void BuildVariableLoadForAccumulatorValue( void BuildVariableLoadForAccumulatorValue(
Variable* variable, FeedbackVectorSlot slot, bool needs_hole_check, Variable* variable, FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode,
TypeofMode typeof_mode = NOT_INSIDE_TYPEOF); TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
void BuildVariableAssignment(Variable* variable, Token::Value op, void BuildVariableAssignment(Variable* variable, Token::Value op,
FeedbackVectorSlot slot, bool needs_hole_check); FeedbackVectorSlot slot,
HoleCheckMode hole_check_mode);
void BuildReturn(); void BuildReturn();
void BuildReThrow(); void BuildReThrow();
......
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