Revision: 10244
Author: [email protected]
Date: Tue Dec 13 09:10:34 2011
Log: [hydrogen] don't bailout assignments to consts
If constant variable is allocated in CONTEXT
Patch by Fedor Indutny <[email protected]>.
BUG=
TEST=
[email protected]
Review URL: http://codereview.chromium.org/8857001
http://code.google.com/p/v8/source/detail?r=10244
Modified:
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Dec 9
01:50:30 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Tue Dec 13
09:10:34 2011
@@ -2306,7 +2306,11 @@
if (instr->hydrogen()->RequiresHoleCheck()) {
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(result, ip);
- DeoptimizeIf(eq, instr->environment());
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(eq, instr->environment());
+ } else {
+ __ mov(result, Operand(factory()->undefined_value()), LeaveCC, eq);
+ }
}
}
@@ -2314,14 +2318,22 @@
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
+ Register scratch = scratch0();
MemOperand target = ContextOperand(context, instr->slot_index());
+
+ Label skip_assignment;
+
if (instr->hydrogen()->RequiresHoleCheck()) {
- Register scratch = scratch0();
__ ldr(scratch, target);
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(scratch, ip);
- DeoptimizeIf(eq, instr->environment());
- }
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(eq, instr->environment());
+ } else {
+ __ b(ne, &skip_assignment);
+ }
+ }
+
__ str(value, target);
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
@@ -2330,12 +2342,14 @@
__ RecordWriteContextSlot(context,
target.offset(),
value,
- scratch0(),
+ scratch,
kLRHasBeenSaved,
kSaveFPRegs,
EMIT_REMEMBERED_SET,
check_needed);
}
+
+ __ bind(&skip_assignment);
}
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Fri Dec 9 01:50:30
2011
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Tue Dec 13 09:10:34
2011
@@ -3449,28 +3449,45 @@
public:
enum Mode {
// Perform a normal load of the context slot without checking its
value.
- kLoad,
+ kNoCheck,
// Load and check the value of the context slot. Deoptimize if it's the
// hole value. This is used for checking for loading of uninitialized
// harmony bindings where we deoptimize into full-codegen generated
code
// which will subsequently throw a reference error.
- kLoadCheck
+ kCheckDeoptimize,
+ // Load and check the value of the context slot. Return undefined if
it's
+ // the hole value. This is used for non-harmony const assignments
+ kCheckReturnUndefined
};
HLoadContextSlot(HValue* context, Variable* var)
: HUnaryOperation(context), slot_index_(var->index()) {
ASSERT(var->IsContextSlot());
- mode_ = (var->mode() == LET || var->mode() == CONST_HARMONY)
- ? kLoadCheck : kLoad;
+ switch (var->mode()) {
+ case LET:
+ case CONST_HARMONY:
+ mode_ = kCheckDeoptimize;
+ break;
+ case CONST:
+ mode_ = kCheckReturnUndefined;
+ break;
+ default:
+ mode_ = kNoCheck;
+ }
set_representation(Representation::Tagged());
SetFlag(kUseGVN);
SetFlag(kDependsOnContextSlots);
}
int slot_index() const { return slot_index_; }
+ Mode mode() const { return mode_; }
+
+ bool DeoptimizesOnHole() {
+ return mode_ == kCheckDeoptimize;
+ }
bool RequiresHoleCheck() {
- return mode_ == kLoadCheck;
+ return mode_ != kNoCheck;
}
virtual Representation RequiredInputRepresentation(int index) {
@@ -3498,12 +3515,14 @@
enum Mode {
// Perform a normal store to the context slot without checking its
previous
// value.
- kAssign,
+ kNoCheck,
// Check the previous value of the context slot and deoptimize if it's
the
// hole value. This is used for checking for assignments to
uninitialized
// harmony bindings where we deoptimize into full-codegen generated
code
// which will subsequently throw a reference error.
- kAssignCheck
+ kCheckDeoptimize,
+ // Check the previous value and ignore assignment if it isn't a hole
value
+ kCheckIgnoreAssignment
};
HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue*
value)
@@ -3521,9 +3540,13 @@
bool NeedsWriteBarrier() {
return StoringValueNeedsWriteBarrier(value());
}
+
+ bool DeoptimizesOnHole() {
+ return mode_ == kCheckDeoptimize;
+ }
bool RequiresHoleCheck() {
- return mode_ == kAssignCheck;
+ return mode_ != kNoCheck;
}
virtual Representation RequiredInputRepresentation(int index) {
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri Dec 9 01:50:30 2011
+++ /branches/bleeding_edge/src/hydrogen.cc Tue Dec 13 09:10:34 2011
@@ -3285,9 +3285,6 @@
}
case Variable::CONTEXT: {
- if (variable->mode() == CONST) {
- return Bailout("reference to const context slot");
- }
HValue* context = BuildContextChainWalk(variable);
HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context,
variable);
return ast_context()->ReturnInstruction(instr, expr->id());
@@ -3805,8 +3802,8 @@
if (proxy != NULL) {
Variable* var = proxy->var();
- if (var->mode() == CONST || var->mode() == LET) {
- return Bailout("unsupported let or const compound assignment");
+ if (var->mode() == LET) {
+ return Bailout("unsupported let compound assignment");
}
CHECK_ALIVE(VisitForValue(operation));
@@ -3821,6 +3818,9 @@
case Variable::PARAMETER:
case Variable::LOCAL:
+ if (var->mode() == CONST) {
+ return Bailout("unsupported const compound assignment");
+ }
Bind(var, Top());
break;
@@ -3840,11 +3840,24 @@
}
}
}
+
+ HStoreContextSlot::Mode mode;
+
+ switch (var->mode()) {
+ case LET:
+ mode = HStoreContextSlot::kCheckDeoptimize;
+ break;
+ case CONST:
+ return ast_context()->ReturnValue(Pop());
+ case CONST_HARMONY:
+ // This case is checked statically so no need to
+ // perform checks here
+ UNREACHABLE();
+ default:
+ mode = HStoreContextSlot::kNoCheck;
+ }
HValue* context = BuildContextChainWalk(var);
- HStoreContextSlot::Mode mode =
- (var->mode() == LET || var->mode() == CONST_HARMONY)
- ? HStoreContextSlot::kAssignCheck : HStoreContextSlot::kAssign;
HStoreContextSlot* instr =
new(zone()) HStoreContextSlot(context, var->index(), mode,
Top());
AddInstruction(instr);
@@ -3955,17 +3968,19 @@
HandlePropertyAssignment(expr);
} else if (proxy != NULL) {
Variable* var = proxy->var();
+
if (var->mode() == CONST) {
if (expr->op() != Token::INIT_CONST) {
- return Bailout("non-initializer assignment to const");
- }
- if (!var->IsStackAllocated()) {
- return Bailout("assignment to const context slot");
- }
- // We insert a use of the old value to detect unsupported uses of
const
- // variables (e.g. initialization inside a loop).
- HValue* old_value = environment()->Lookup(var);
- AddInstruction(new HUseConst(old_value));
+ CHECK_ALIVE(VisitForValue(expr->value()));
+ return ast_context()->ReturnValue(Pop());
+ }
+
+ if (var->IsStackAllocated()) {
+ // We insert a use of the old value to detect unsupported uses of
const
+ // variables (e.g. initialization inside a loop).
+ HValue* old_value = environment()->Lookup(var);
+ AddInstruction(new HUseConst(old_value));
+ }
} else if (var->mode() == CONST_HARMONY) {
if (expr->op() != Token::INIT_CONST_HARMONY) {
return Bailout("non-initializer assignment to const");
@@ -4004,7 +4019,6 @@
}
case Variable::CONTEXT: {
- ASSERT(var->mode() != CONST);
// Bail out if we try to mutate a parameter value in a function
using
// the arguments object. We do not (yet) correctly handle the
// arguments property of the function.
@@ -4020,17 +4034,32 @@
}
CHECK_ALIVE(VisitForValue(expr->value()));
- HValue* context = BuildContextChainWalk(var);
HStoreContextSlot::Mode mode;
if (expr->op() == Token::ASSIGN) {
- mode = (var->mode() == LET || var->mode() == CONST_HARMONY)
- ? HStoreContextSlot::kAssignCheck :
HStoreContextSlot::kAssign;
+ switch (var->mode()) {
+ case LET:
+ mode = HStoreContextSlot::kCheckDeoptimize;
+ break;
+ case CONST:
+ return ast_context()->ReturnValue(Pop());
+ case CONST_HARMONY:
+ // This case is checked statically so no need to
+ // perform checks here
+ UNREACHABLE();
+ default:
+ mode = HStoreContextSlot::kNoCheck;
+ }
+ } else if (expr->op() == Token::INIT_VAR ||
+ expr->op() == Token::INIT_LET ||
+ expr->op() == Token::INIT_CONST_HARMONY) {
+ mode = HStoreContextSlot::kNoCheck;
} else {
- ASSERT(expr->op() == Token::INIT_VAR ||
- expr->op() == Token::INIT_LET ||
- expr->op() == Token::INIT_CONST_HARMONY);
- mode = HStoreContextSlot::kAssign;
- }
+ ASSERT(expr->op() == Token::INIT_CONST);
+
+ mode = HStoreContextSlot::kCheckIgnoreAssignment;
+ }
+
+ HValue* context = BuildContextChainWalk(var);
HStoreContextSlot* instr = new(zone()) HStoreContextSlot(
context, var->index(), mode, Top());
AddInstruction(instr);
@@ -5643,7 +5672,7 @@
HValue* context = BuildContextChainWalk(var);
HStoreContextSlot::Mode mode =
(var->mode() == LET || var->mode() == CONST_HARMONY)
- ? HStoreContextSlot::kAssignCheck : HStoreContextSlot::kAssign;
+ ? HStoreContextSlot::kCheckDeoptimize :
HStoreContextSlot::kNoCheck;
HStoreContextSlot* instr =
new(zone()) HStoreContextSlot(context, var->index(), mode,
after);
AddInstruction(instr);
@@ -6251,7 +6280,7 @@
if (var->IsContextSlot()) {
HValue* context = environment()->LookupContext();
HStoreContextSlot* store = new HStoreContextSlot(
- context, var->index(), HStoreContextSlot::kAssign, value);
+ context, var->index(), HStoreContextSlot::kNoCheck, value);
AddInstruction(store);
if (store->HasObservableSideEffects()) AddSimulate(proxy->id());
} else {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Dec 9
01:50:30 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Dec 13
09:10:34 2011
@@ -2165,9 +2165,17 @@
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
__ mov(result, ContextOperand(context, instr->slot_index()));
+
if (instr->hydrogen()->RequiresHoleCheck()) {
__ cmp(result, factory()->the_hole_value());
- DeoptimizeIf(equal, instr->environment());
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(equal, instr->environment());
+ } else {
+ Label is_not_hole;
+ __ j(not_equal, &is_not_hole, Label::kNear);
+ __ mov(result, factory()->undefined_value());
+ __ bind(&is_not_hole);
+ }
}
}
@@ -2175,11 +2183,19 @@
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
+
+ Label skip_assignment;
+
Operand target = ContextOperand(context, instr->slot_index());
if (instr->hydrogen()->RequiresHoleCheck()) {
__ cmp(target, factory()->the_hole_value());
- DeoptimizeIf(equal, instr->environment());
- }
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(equal, instr->environment());
+ } else {
+ __ j(not_equal, &skip_assignment, Label::kNear);
+ }
+ }
+
__ mov(target, value);
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
@@ -2195,6 +2211,8 @@
EMIT_REMEMBERED_SET,
check_needed);
}
+
+ __ bind(&skip_assignment);
}
=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Mon Dec 12
00:48:39 2011
+++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Tue Dec 13
09:10:34 2011
@@ -2180,10 +2180,19 @@
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
Register context = ToRegister(instr->context());
Register result = ToRegister(instr->result());
+
__ lw(result, ContextOperand(context, instr->slot_index()));
if (instr->hydrogen()->RequiresHoleCheck()) {
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- DeoptimizeIf(eq, instr->environment(), result, Operand(at));
+
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(eq, instr->environment(), result, Operand(at));
+ } else {
+ Label is_not_hole;
+ __ Branch(&is_not_hole, ne, result, Operand(at));
+ __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
+ __ bind(&is_not_hole);
+ }
}
}
@@ -2191,13 +2200,22 @@
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
+ Register scratch = scratch0();
MemOperand target = ContextOperand(context, instr->slot_index());
+
+ Label skip_assignment;
+
if (instr->hydrogen()->RequiresHoleCheck()) {
- Register scratch = scratch0();
__ lw(scratch, target);
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
- }
+
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(eq, instr->environment(), scratch, Operand(at));
+ } else {
+ __ Branch(&skip_assignment, ne, scratch, Operand(at));
+ }
+ }
+
__ sw(value, target);
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
@@ -2212,6 +2230,8 @@
EMIT_REMEMBERED_SET,
check_needed);
}
+
+ __ bind(&skip_assignment);
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Dec 9
01:50:30 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Dec 13
09:10:34 2011
@@ -2069,7 +2069,14 @@
__ movq(result, ContextOperand(context, instr->slot_index()));
if (instr->hydrogen()->RequiresHoleCheck()) {
__ CompareRoot(result, Heap::kTheHoleValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(equal, instr->environment());
+ } else {
+ Label is_not_hole;
+ __ j(not_equal, &is_not_hole, Label::kNear);
+ __ movq(result, factory()->undefined_value(), RelocInfo::NONE);
+ __ bind(&is_not_hole);
+ }
}
}
@@ -2077,12 +2084,20 @@
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
Register context = ToRegister(instr->context());
Register value = ToRegister(instr->value());
+
Operand target = ContextOperand(context, instr->slot_index());
+
+ Label skip_assignment;
if (instr->hydrogen()->RequiresHoleCheck()) {
__ CompareRoot(target, Heap::kTheHoleValueRootIndex);
- DeoptimizeIf(equal, instr->environment());
+ if (instr->hydrogen()->DeoptimizesOnHole()) {
+ DeoptimizeIf(equal, instr->environment());
+ } else {
+ __ j(not_equal, &skip_assignment, Label::kNear);
+ }
}
__ movq(target, value);
+
if (instr->hydrogen()->NeedsWriteBarrier()) {
HType type = instr->hydrogen()->value()->type();
SmiCheck check_needed =
@@ -2097,6 +2112,8 @@
EMIT_REMEMBERED_SET,
check_needed);
}
+
+ __ bind(&skip_assignment);
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev