Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 9d5aa2be31fa7206456e93d1257eb4320e0abf30..4044f7fff130bc71fa0378dc105d10ac7fd044d5 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -2955,6 +2955,19 @@ void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
} |
+HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { |
+ ASSERT(var->IsContextSlot()); |
+ HInstruction* context = new HContext; |
+ AddInstruction(context); |
+ int length = graph()->info()->scope()->ContextChainLength(var->scope()); |
+ while (length-- > 0) { |
+ context = new HOuterContext(context); |
+ AddInstruction(context); |
+ } |
+ return context; |
+} |
+ |
+ |
void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
Variable* variable = expr->AsVariable(); |
if (variable == NULL) { |
@@ -2968,16 +2981,9 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
if (variable->mode() == Variable::CONST) { |
BAILOUT("reference to const context slot"); |
} |
- Slot* slot = variable->AsSlot(); |
- CompilationInfo* info = graph()->info(); |
- int context_chain_length = info->function()->scope()-> |
- ContextChainLength(slot->var()->scope()); |
- ASSERT(context_chain_length >= 0); |
- // TODO(antonm): if slot's value is not modified by closures, instead |
antonm
2011/02/03 13:14:30
may we keep this TODO?
|
- // of reading it out of context, we could just embed the value as |
- // a constant. |
- HLoadContextSlot* instr = |
- new HLoadContextSlot(context_chain_length, slot->index()); |
+ HValue* context = BuildContextChainWalk(variable); |
+ int index = variable->AsSlot()->index(); |
+ HLoadContextSlot* instr = new HLoadContextSlot(context, index); |
ast_context()->ReturnInstruction(instr, expr->id()); |
} else if (variable->is_global()) { |
LookupResult lookup; |
@@ -3515,35 +3521,48 @@ void HGraphBuilder::VisitAssignment(Assignment* expr) { |
if (proxy->IsArguments()) BAILOUT("assignment to arguments"); |
// Handle the assignment. |
- if (var->is_global()) { |
+ if (var->IsStackAllocated()) { |
+ HValue* value = NULL; |
+ // Handle stack-allocated variables on the right-hand side directly. |
+ // We do not allow the arguments object to occur in a context where it |
+ // may escape, but assignments to stack-allocated locals are |
+ // permitted. Handling such assignments here bypasses the check for |
+ // the arguments object in VisitVariableProxy. |
+ Variable* rhs_var = expr->value()->AsVariableProxy()->AsVariable(); |
+ if (rhs_var != NULL && rhs_var->IsStackAllocated()) { |
+ value = environment()->Lookup(rhs_var); |
+ } else { |
+ VISIT_FOR_VALUE(expr->value()); |
+ value = Pop(); |
+ } |
+ Bind(var, value); |
+ ast_context()->ReturnValue(value); |
+ |
+ } else if (var->IsContextSlot() && var->mode() != Variable::CONST) { |
+ VISIT_FOR_VALUE(expr->value()); |
+ HValue* context = BuildContextChainWalk(var); |
+ int index = var->AsSlot()->index(); |
+ HStoreContextSlot* instr = new HStoreContextSlot(context, index, Top()); |
+ AddInstruction(instr); |
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
+ ast_context()->ReturnValue(Pop()); |
+ |
+ } else if (var->is_global()) { |
VISIT_FOR_VALUE(expr->value()); |
HandleGlobalVariableAssignment(var, |
Top(), |
expr->position(), |
expr->AssignmentId()); |
- } else if (var->IsStackAllocated()) { |
- // We allow reference to the arguments object only in assignemtns |
- // to local variables to make sure that the arguments object does |
- // not escape and is not modified. |
- VariableProxy* rhs = expr->value()->AsVariableProxy(); |
- if (rhs != NULL && |
- rhs->var()->IsStackAllocated() && |
- environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) { |
- Push(environment()->Lookup(rhs->var())); |
- } else { |
- VISIT_FOR_VALUE(expr->value()); |
- } |
- Bind(proxy->var(), Top()); |
+ ast_context()->ReturnValue(Pop()); |
+ |
} else { |
- BAILOUT("Assigning to no non-stack-allocated/non-global variable"); |
+ BAILOUT("assignment to LOOKUP or const CONTEXT variable"); |
} |
- // Return the value. |
- ast_context()->ReturnValue(Pop()); |
} else if (prop != NULL) { |
HandlePropertyAssignment(expr); |
} else { |
- BAILOUT("unsupported invalid lhs"); |
+ BAILOUT("invalid left-hand side in assignment"); |
} |
} |
@@ -4422,7 +4441,10 @@ void HGraphBuilder::VisitCall(Call* expr) { |
if (known_global_function) { |
// Push the global object instead of the global receiver because |
// code generated by the full code generator expects it. |
- PushAndAdd(new HGlobalObject); |
+ HContext* context = new HContext; |
+ HGlobalObject* global_object = new HGlobalObject(context); |
+ AddInstruction(context); |
+ PushAndAdd(global_object); |
VisitArgumentList(expr->arguments()); |
CHECK_BAILOUT; |
@@ -4431,7 +4453,7 @@ void HGraphBuilder::VisitCall(Call* expr) { |
AddInstruction(new HCheckFunction(function, expr->target())); |
// Replace the global object with the global receiver. |
- HGlobalReceiver* global_receiver = new HGlobalReceiver; |
+ HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object); |
// Index of the receiver from the top of the expression stack. |
const int receiver_index = argument_count - 1; |
AddInstruction(global_receiver); |
@@ -4458,7 +4480,9 @@ void HGraphBuilder::VisitCall(Call* expr) { |
call = new HCallKnownGlobal(expr->target(), argument_count); |
} else { |
- PushAndAdd(new HGlobalObject); |
+ HContext* context = new HContext; |
+ AddInstruction(context); |
+ PushAndAdd(new HGlobalObject(context)); |
VisitArgumentList(expr->arguments()); |
CHECK_BAILOUT; |
@@ -4466,7 +4490,11 @@ void HGraphBuilder::VisitCall(Call* expr) { |
} |
} else { |
- PushAndAdd(new HGlobalReceiver); |
+ HContext* context = new HContext; |
+ HGlobalObject* global_object = new HGlobalObject(context); |
+ AddInstruction(context); |
+ AddInstruction(global_object); |
+ PushAndAdd(new HGlobalReceiver(global_object)); |
VisitArgumentList(expr->arguments()); |
CHECK_BAILOUT; |