Commit 04c51b21 authored by bjaideep's avatar bjaideep Committed by Commit bot

PPC/s390: Use Variable::binding_needs_init() to determine hole initialization

Port 6768456d

Original commit message:

    The old code was using VariableMode, but that signal is both
    over-pessimistic (some CONST and LET variables need no hole-initialization)
    and inconsistent with other uses of the InitializationFlag enum (such
    as %LoadLookupSlot).

    This changes no observable behavior, but removes unnecessary hole
    initialization and hole checks in a few places, including
    block-scoped function declarations, super property lookups,
    and new.target.

R=adamk@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com, mbrandy@us.ibm.com

BUG=
LOG=N

Review-Url: https://codereview.chromium.org/2229383004
Cr-Commit-Position: refs/heads/master@{#38551}
parent d1ab9f12
...@@ -723,13 +723,8 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { ...@@ -723,13 +723,8 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
void FullCodeGenerator::VisitVariableDeclaration( void FullCodeGenerator::VisitVariableDeclaration(
VariableDeclaration* declaration) { VariableDeclaration* declaration) {
// If it was not possible to allocate the variable at compile time, we
// need to "declare" it at runtime to make sure it actually exists in the
// local context.
VariableProxy* proxy = declaration->proxy(); VariableProxy* proxy = declaration->proxy();
VariableMode mode = declaration->mode();
Variable* variable = proxy->var(); Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST;
switch (variable->location()) { switch (variable->location()) {
case VariableLocation::GLOBAL: case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: { case VariableLocation::UNALLOCATED: {
...@@ -742,7 +737,7 @@ void FullCodeGenerator::VisitVariableDeclaration( ...@@ -742,7 +737,7 @@ void FullCodeGenerator::VisitVariableDeclaration(
} }
case VariableLocation::PARAMETER: case VariableLocation::PARAMETER:
case VariableLocation::LOCAL: case VariableLocation::LOCAL:
if (hole_init) { if (variable->binding_needs_init()) {
Comment cmnt(masm_, "[ VariableDeclaration"); Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ StoreP(ip, StackOperand(variable)); __ StoreP(ip, StackOperand(variable));
...@@ -750,7 +745,7 @@ void FullCodeGenerator::VisitVariableDeclaration( ...@@ -750,7 +745,7 @@ void FullCodeGenerator::VisitVariableDeclaration(
break; break;
case VariableLocation::CONTEXT: case VariableLocation::CONTEXT:
if (hole_init) { if (variable->binding_needs_init()) {
Comment cmnt(masm_, "[ VariableDeclaration"); Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable); EmitDebugCheckDeclarationContext(variable);
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
...@@ -762,8 +757,8 @@ void FullCodeGenerator::VisitVariableDeclaration( ...@@ -762,8 +757,8 @@ void FullCodeGenerator::VisitVariableDeclaration(
case VariableLocation::LOOKUP: { case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration"); Comment cmnt(masm_, "[ VariableDeclaration");
DCHECK_EQ(VAR, mode); DCHECK_EQ(VAR, variable->mode());
DCHECK(!hole_init); DCHECK(!variable->binding_needs_init());
__ mov(r5, Operand(variable->name())); __ mov(r5, Operand(variable->name()));
__ Push(r5); __ Push(r5);
__ CallRuntime(Runtime::kDeclareEvalVar); __ CallRuntime(Runtime::kDeclareEvalVar);
...@@ -1243,14 +1238,15 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, ...@@ -1243,14 +1238,15 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
} else if (var->mode() == DYNAMIC_LOCAL) { } else if (var->mode() == DYNAMIC_LOCAL) {
Variable* local = var->local_if_not_shadowed(); Variable* local = var->local_if_not_shadowed();
__ LoadP(r3, ContextSlotOperandCheckExtensions(local, slow)); __ LoadP(r3, ContextSlotOperandCheckExtensions(local, slow));
if (local->mode() == LET || local->mode() == CONST) { if (local->binding_needs_init()) {
__ CompareRoot(r3, Heap::kTheHoleValueRootIndex); __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
__ bne(done); __ bne(done);
__ mov(r3, Operand(var->name())); __ mov(r3, Operand(var->name()));
__ push(r3); __ push(r3);
__ CallRuntime(Runtime::kThrowReferenceError); __ CallRuntime(Runtime::kThrowReferenceError);
} else {
__ b(done);
} }
__ b(done);
} }
} }
...@@ -1293,18 +1289,15 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ...@@ -1293,18 +1289,15 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable"); : "[ Stack variable");
if (NeedsHoleCheckForLoad(proxy)) { if (NeedsHoleCheckForLoad(proxy)) {
// Throw a reference error when using an uninitialized let/const
// binding in harmony mode.
Label done; Label done;
// Let and const need a read barrier.
GetVar(r3, var); GetVar(r3, var);
__ CompareRoot(r3, Heap::kTheHoleValueRootIndex); __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
__ bne(&done); __ bne(&done);
if (var->mode() == LET || var->mode() == CONST) { __ mov(r3, Operand(var->name()));
// Throw a reference error when using an uninitialized let/const __ push(r3);
// binding in harmony mode. __ CallRuntime(Runtime::kThrowReferenceError);
__ mov(r3, Operand(var->name()));
__ push(r3);
__ CallRuntime(Runtime::kThrowReferenceError);
}
__ bind(&done); __ bind(&done);
context()->Plug(r3); context()->Plug(r3);
break; break;
...@@ -2187,37 +2180,26 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, ...@@ -2187,37 +2180,26 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
EmitLoadStoreICSlot(slot); EmitLoadStoreICSlot(slot);
CallStoreIC(); CallStoreIC();
} else if (var->mode() == LET && op != Token::INIT) { } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) {
// Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label assign;
MemOperand location = VarOperand(var, r4);
__ LoadP(r6, location);
__ CompareRoot(r6, Heap::kTheHoleValueRootIndex);
__ bne(&assign);
__ mov(r6, Operand(var->name()));
__ push(r6);
__ CallRuntime(Runtime::kThrowReferenceError);
// Perform the assignment.
__ bind(&assign);
EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->mode() == CONST && op != Token::INIT) {
// Assignment to const variable needs a write barrier.
DCHECK(!var->IsLookupSlot()); DCHECK(!var->IsLookupSlot());
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label const_error;
MemOperand location = VarOperand(var, r4); MemOperand location = VarOperand(var, r4);
__ LoadP(r6, location); // Perform an initialization check for lexically declared variables.
__ CompareRoot(r6, Heap::kTheHoleValueRootIndex); if (var->binding_needs_init()) {
__ bne(&const_error); Label assign;
__ mov(r6, Operand(var->name())); __ LoadP(r6, location);
__ push(r6); __ CompareRoot(r6, Heap::kTheHoleValueRootIndex);
__ CallRuntime(Runtime::kThrowReferenceError); __ bne(&assign);
__ bind(&const_error); __ mov(r6, Operand(var->name()));
__ CallRuntime(Runtime::kThrowConstAssignError); __ push(r6);
__ CallRuntime(Runtime::kThrowReferenceError);
__ bind(&assign);
}
if (var->mode() == CONST) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} else {
EmitStoreToStackLocalOrContextSlot(var, location);
}
} else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
// Initializing assignment to const {this} needs a write barrier. // Initializing assignment to const {this} needs a write barrier.
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
......
...@@ -699,13 +699,8 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) { ...@@ -699,13 +699,8 @@ void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
void FullCodeGenerator::VisitVariableDeclaration( void FullCodeGenerator::VisitVariableDeclaration(
VariableDeclaration* declaration) { VariableDeclaration* declaration) {
// If it was not possible to allocate the variable at compile time, we
// need to "declare" it at runtime to make sure it actually exists in the
// local context.
VariableProxy* proxy = declaration->proxy(); VariableProxy* proxy = declaration->proxy();
VariableMode mode = declaration->mode();
Variable* variable = proxy->var(); Variable* variable = proxy->var();
bool hole_init = mode == LET || mode == CONST;
switch (variable->location()) { switch (variable->location()) {
case VariableLocation::GLOBAL: case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: { case VariableLocation::UNALLOCATED: {
...@@ -718,7 +713,7 @@ void FullCodeGenerator::VisitVariableDeclaration( ...@@ -718,7 +713,7 @@ void FullCodeGenerator::VisitVariableDeclaration(
} }
case VariableLocation::PARAMETER: case VariableLocation::PARAMETER:
case VariableLocation::LOCAL: case VariableLocation::LOCAL:
if (hole_init) { if (variable->binding_needs_init()) {
Comment cmnt(masm_, "[ VariableDeclaration"); Comment cmnt(masm_, "[ VariableDeclaration");
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ StoreP(ip, StackOperand(variable)); __ StoreP(ip, StackOperand(variable));
...@@ -726,7 +721,7 @@ void FullCodeGenerator::VisitVariableDeclaration( ...@@ -726,7 +721,7 @@ void FullCodeGenerator::VisitVariableDeclaration(
break; break;
case VariableLocation::CONTEXT: case VariableLocation::CONTEXT:
if (hole_init) { if (variable->binding_needs_init()) {
Comment cmnt(masm_, "[ VariableDeclaration"); Comment cmnt(masm_, "[ VariableDeclaration");
EmitDebugCheckDeclarationContext(variable); EmitDebugCheckDeclarationContext(variable);
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex); __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
...@@ -738,8 +733,8 @@ void FullCodeGenerator::VisitVariableDeclaration( ...@@ -738,8 +733,8 @@ void FullCodeGenerator::VisitVariableDeclaration(
case VariableLocation::LOOKUP: { case VariableLocation::LOOKUP: {
Comment cmnt(masm_, "[ VariableDeclaration"); Comment cmnt(masm_, "[ VariableDeclaration");
DCHECK_EQ(VAR, mode); DCHECK_EQ(VAR, variable->mode());
DCHECK(!hole_init); DCHECK(!variable->binding_needs_init());
__ mov(r4, Operand(variable->name())); __ mov(r4, Operand(variable->name()));
__ Push(r4); __ Push(r4);
__ CallRuntime(Runtime::kDeclareEvalVar); __ CallRuntime(Runtime::kDeclareEvalVar);
...@@ -1207,14 +1202,15 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy, ...@@ -1207,14 +1202,15 @@ void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
} else if (var->mode() == DYNAMIC_LOCAL) { } else if (var->mode() == DYNAMIC_LOCAL) {
Variable* local = var->local_if_not_shadowed(); Variable* local = var->local_if_not_shadowed();
__ LoadP(r2, ContextSlotOperandCheckExtensions(local, slow)); __ LoadP(r2, ContextSlotOperandCheckExtensions(local, slow));
if (local->mode() == LET || local->mode() == CONST) { if (local->binding_needs_init()) {
__ CompareRoot(r2, Heap::kTheHoleValueRootIndex); __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
__ bne(done); __ bne(done);
__ mov(r2, Operand(var->name())); __ mov(r2, Operand(var->name()));
__ push(r2); __ push(r2);
__ CallRuntime(Runtime::kThrowReferenceError); __ CallRuntime(Runtime::kThrowReferenceError);
} else {
__ b(done);
} }
__ b(done);
} }
} }
...@@ -1255,18 +1251,15 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy, ...@@ -1255,18 +1251,15 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
: "[ Stack variable"); : "[ Stack variable");
if (NeedsHoleCheckForLoad(proxy)) { if (NeedsHoleCheckForLoad(proxy)) {
// Throw a reference error when using an uninitialized let/const
// binding in harmony mode.
Label done; Label done;
// Let and const need a read barrier.
GetVar(r2, var); GetVar(r2, var);
__ CompareRoot(r2, Heap::kTheHoleValueRootIndex); __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
__ bne(&done); __ bne(&done);
if (var->mode() == LET || var->mode() == CONST) { __ mov(r2, Operand(var->name()));
// Throw a reference error when using an uninitialized let/const __ push(r2);
// binding in harmony mode. __ CallRuntime(Runtime::kThrowReferenceError);
__ mov(r2, Operand(var->name()));
__ push(r2);
__ CallRuntime(Runtime::kThrowReferenceError);
}
__ bind(&done); __ bind(&done);
context()->Plug(r2); context()->Plug(r2);
break; break;
...@@ -2141,37 +2134,27 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op, ...@@ -2141,37 +2134,27 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
EmitLoadStoreICSlot(slot); EmitLoadStoreICSlot(slot);
CallStoreIC(); CallStoreIC();
} else if (var->mode() == LET && op != Token::INIT) { } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) {
// Non-initializing assignment to let variable needs a write barrier. // Non-initializing assignment to let variable needs a write barrier.
DCHECK(!var->IsLookupSlot()); DCHECK(!var->IsLookupSlot());
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label assign;
MemOperand location = VarOperand(var, r3);
__ LoadP(r5, location);
__ CompareRoot(r5, Heap::kTheHoleValueRootIndex);
__ bne(&assign);
__ mov(r5, Operand(var->name()));
__ push(r5);
__ CallRuntime(Runtime::kThrowReferenceError);
// Perform the assignment.
__ bind(&assign);
EmitStoreToStackLocalOrContextSlot(var, location);
} else if (var->mode() == CONST && op != Token::INIT) {
// Assignment to const variable needs a write barrier.
DCHECK(!var->IsLookupSlot());
DCHECK(var->IsStackAllocated() || var->IsContextSlot());
Label const_error;
MemOperand location = VarOperand(var, r3); MemOperand location = VarOperand(var, r3);
__ LoadP(r5, location); // Perform an initialization check for lexically declared variables.
__ CompareRoot(r5, Heap::kTheHoleValueRootIndex); if (var->binding_needs_init()) {
__ bne(&const_error, Label::kNear); Label assign;
__ mov(r5, Operand(var->name())); __ LoadP(r5, location);
__ push(r5); __ CompareRoot(r5, Heap::kTheHoleValueRootIndex);
__ CallRuntime(Runtime::kThrowReferenceError); __ bne(&assign);
__ bind(&const_error); __ mov(r5, Operand(var->name()));
__ CallRuntime(Runtime::kThrowConstAssignError); __ push(r5);
__ CallRuntime(Runtime::kThrowReferenceError);
__ bind(&assign);
}
if (var->mode() == CONST) {
__ CallRuntime(Runtime::kThrowConstAssignError);
} else {
EmitStoreToStackLocalOrContextSlot(var, location);
}
} else if (var->is_this() && var->mode() == CONST && op == Token::INIT) { } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
// Initializing assignment to const {this} needs a write barrier. // Initializing assignment to const {this} needs a write barrier.
DCHECK(var->IsStackAllocated() || var->IsContextSlot()); DCHECK(var->IsStackAllocated() || var->IsContextSlot());
......
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