[hydrogen] don't bailout assignments to consts
If constant variable is allocated in CONTEXT Patch by Fedor Indutny <fedor.indutny@gmail.com>. BUG= TEST= R=vegorov@chromium.org Review URL: http://codereview.chromium.org/8857001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10244 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
76b48da7ef
commit
626454a61a
@ -2306,7 +2306,11 @@ void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ cmp(result, ip);
|
||||
if (instr->hydrogen()->DeoptimizesOnHole()) {
|
||||
DeoptimizeIf(eq, instr->environment());
|
||||
} else {
|
||||
__ mov(result, Operand(factory()->undefined_value()), LeaveCC, eq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2314,14 +2318,22 @@ void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register value = ToRegister(instr->value());
|
||||
MemOperand target = ContextOperand(context, instr->slot_index());
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
Register scratch = scratch0();
|
||||
MemOperand target = ContextOperand(context, instr->slot_index());
|
||||
|
||||
Label skip_assignment;
|
||||
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
__ ldr(scratch, target);
|
||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||
__ cmp(scratch, ip);
|
||||
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 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
__ RecordWriteContextSlot(context,
|
||||
target.offset(),
|
||||
value,
|
||||
scratch0(),
|
||||
scratch,
|
||||
kLRHasBeenSaved,
|
||||
kSaveFPRegs,
|
||||
EMIT_REMEMBERED_SET,
|
||||
check_needed);
|
||||
}
|
||||
|
||||
__ bind(&skip_assignment);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3449,28 +3449,45 @@ class HLoadContextSlot: public HUnaryOperation {
|
||||
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 @@ class HStoreContextSlot: public HTemplateInstruction<2> {
|
||||
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)
|
||||
@ -3522,8 +3541,12 @@ class HStoreContextSlot: public HTemplateInstruction<2> {
|
||||
return StoringValueNeedsWriteBarrier(value());
|
||||
}
|
||||
|
||||
bool DeoptimizesOnHole() {
|
||||
return mode_ == kCheckDeoptimize;
|
||||
}
|
||||
|
||||
bool RequiresHoleCheck() {
|
||||
return mode_ == kAssignCheck;
|
||||
return mode_ != kNoCheck;
|
||||
}
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
|
@ -3285,9 +3285,6 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
|
||||
}
|
||||
|
||||
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 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
||||
|
||||
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 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
||||
|
||||
case Variable::PARAMETER:
|
||||
case Variable::LOCAL:
|
||||
if (var->mode() == CONST) {
|
||||
return Bailout("unsupported const compound assignment");
|
||||
}
|
||||
Bind(var, Top());
|
||||
break;
|
||||
|
||||
@ -3841,10 +3841,23 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
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");
|
||||
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 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
}
|
||||
|
||||
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 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) {
|
||||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
ASSERT(expr->op() == Token::INIT_VAR ||
|
||||
expr->op() == Token::INIT_LET ||
|
||||
expr->op() == Token::INIT_CONST_HARMONY);
|
||||
mode = 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_CONST);
|
||||
|
||||
mode = HStoreContextSlot::kCheckIgnoreAssignment;
|
||||
}
|
||||
|
||||
HValue* context = BuildContextChainWalk(var);
|
||||
HStoreContextSlot* instr = new(zone()) HStoreContextSlot(
|
||||
context, var->index(), mode, Top());
|
||||
AddInstruction(instr);
|
||||
@ -5643,7 +5672,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) {
|
||||
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 @@ void HGraphBuilder::HandleDeclaration(VariableProxy* proxy,
|
||||
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 {
|
||||
|
@ -2165,9 +2165,17 @@ void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
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());
|
||||
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::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
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());
|
||||
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 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
EMIT_REMEMBERED_SET,
|
||||
check_needed);
|
||||
}
|
||||
|
||||
__ bind(&skip_assignment);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2180,10 +2180,19 @@ void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
|
||||
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);
|
||||
|
||||
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::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
Register context = ToRegister(instr->context());
|
||||
Register value = ToRegister(instr->value());
|
||||
MemOperand target = ContextOperand(context, instr->slot_index());
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
Register scratch = scratch0();
|
||||
MemOperand target = ContextOperand(context, instr->slot_index());
|
||||
|
||||
Label skip_assignment;
|
||||
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
__ lw(scratch, target);
|
||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||
|
||||
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 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
EMIT_REMEMBERED_SET,
|
||||
check_needed);
|
||||
}
|
||||
|
||||
__ bind(&skip_assignment);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2069,7 +2069,14 @@ void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
__ movq(result, ContextOperand(context, instr->slot_index()));
|
||||
if (instr->hydrogen()->RequiresHoleCheck()) {
|
||||
__ CompareRoot(result, Heap::kTheHoleValueRootIndex);
|
||||
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::DoLoadContextSlot(LLoadContextSlot* instr) {
|
||||
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);
|
||||
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 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
||||
EMIT_REMEMBERED_SET,
|
||||
check_needed);
|
||||
}
|
||||
|
||||
__ bind(&skip_assignment);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user