Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 3580) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -263,6 +263,13 @@ |
frame_->Drop(); // Value is no longer needed. |
} |
+ // Initialize ThisFunction reference if present. |
+ if (scope_->is_function_scope() && scope_->function() != NULL) { |
+ __ mov(ip, Operand(Factory::the_hole_value())); |
+ frame_->EmitPush(ip); |
+ StoreToSlot(scope_->function()->slot(), NOT_CONST_INIT); |
+ } |
+ |
// Generate code to 'execute' declarations and initialize functions |
// (source elements). In case of an illegal redeclaration we need to |
// handle that instead of processing the declarations. |
@@ -2446,6 +2453,87 @@ |
} |
+void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
+ ASSERT(slot != NULL); |
+ if (slot->type() == Slot::LOOKUP) { |
+ ASSERT(slot->var()->is_dynamic()); |
+ |
+ // For now, just do a runtime call. |
+ frame_->EmitPush(cp); |
+ __ mov(r0, Operand(slot->var()->name())); |
+ frame_->EmitPush(r0); |
+ |
+ if (init_state == CONST_INIT) { |
+ // Same as the case for a normal store, but ignores attribute |
+ // (e.g. READ_ONLY) of context slot so that we can initialize |
+ // const properties (introduced via eval("const foo = (some |
+ // expr);")). Also, uses the current function context instead of |
+ // the top context. |
+ // |
+ // Note that we must declare the foo upon entry of eval(), via a |
+ // context slot declaration, but we cannot initialize it at the |
+ // same time, because the const declaration may be at the end of |
+ // the eval code (sigh...) and the const variable may have been |
+ // used before (where its value is 'undefined'). Thus, we can only |
+ // do the initialization when we actually encounter the expression |
+ // and when the expression operands are defined and valid, and |
+ // thus we need the split into 2 operations: declaration of the |
+ // context slot followed by initialization. |
+ frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
+ } else { |
+ frame_->CallRuntime(Runtime::kStoreContextSlot, 3); |
+ } |
+ // Storing a variable must keep the (new) value on the expression |
+ // stack. This is necessary for compiling assignment expressions. |
+ frame_->EmitPush(r0); |
+ |
+ } else { |
+ ASSERT(!slot->var()->is_dynamic()); |
+ |
+ JumpTarget exit; |
+ if (init_state == CONST_INIT) { |
+ ASSERT(slot->var()->mode() == Variable::CONST); |
+ // Only the first const initialization must be executed (the slot |
+ // still contains 'the hole' value). When the assignment is |
+ // executed, the code is identical to a normal store (see below). |
+ Comment cmnt(masm_, "[ Init const"); |
+ __ ldr(r2, SlotOperand(slot, r2)); |
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
+ __ cmp(r2, ip); |
+ exit.Branch(ne); |
+ } |
+ |
+ // We must execute the store. Storing a variable must keep the |
+ // (new) value on the stack. This is necessary for compiling |
+ // assignment expressions. |
+ // |
+ // Note: We will reach here even with slot->var()->mode() == |
+ // Variable::CONST because of const declarations which will |
+ // initialize consts to 'the hole' value and by doing so, end up |
+ // calling this code. r2 may be loaded with context; used below in |
+ // RecordWrite. |
+ frame_->EmitPop(r0); |
+ __ str(r0, SlotOperand(slot, r2)); |
+ frame_->EmitPush(r0); |
+ if (slot->type() == Slot::CONTEXT) { |
+ // Skip write barrier if the written value is a smi. |
+ __ tst(r0, Operand(kSmiTagMask)); |
+ exit.Branch(eq); |
+ // r2 is loaded with context when calling SlotOperand above. |
+ int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
+ __ mov(r3, Operand(offset)); |
+ __ RecordWrite(r2, r3, r1); |
+ } |
+ // If we definitely did not jump over the assignment, we do not need |
+ // to bind the exit label. Doing so can defeat peephole |
+ // optimization. |
+ if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { |
+ exit.Bind(); |
+ } |
+ } |
+} |
+ |
+ |
void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, |
TypeofState typeof_state, |
Register tmp, |
@@ -4262,83 +4350,7 @@ |
case SLOT: { |
Comment cmnt(masm, "[ Store to Slot"); |
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
- ASSERT(slot != NULL); |
- if (slot->type() == Slot::LOOKUP) { |
- ASSERT(slot->var()->is_dynamic()); |
- |
- // For now, just do a runtime call. |
- frame->EmitPush(cp); |
- __ mov(r0, Operand(slot->var()->name())); |
- frame->EmitPush(r0); |
- |
- if (init_state == CONST_INIT) { |
- // Same as the case for a normal store, but ignores attribute |
- // (e.g. READ_ONLY) of context slot so that we can initialize |
- // const properties (introduced via eval("const foo = (some |
- // expr);")). Also, uses the current function context instead of |
- // the top context. |
- // |
- // Note that we must declare the foo upon entry of eval(), via a |
- // context slot declaration, but we cannot initialize it at the |
- // same time, because the const declaration may be at the end of |
- // the eval code (sigh...) and the const variable may have been |
- // used before (where its value is 'undefined'). Thus, we can only |
- // do the initialization when we actually encounter the expression |
- // and when the expression operands are defined and valid, and |
- // thus we need the split into 2 operations: declaration of the |
- // context slot followed by initialization. |
- frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
- } else { |
- frame->CallRuntime(Runtime::kStoreContextSlot, 3); |
- } |
- // Storing a variable must keep the (new) value on the expression |
- // stack. This is necessary for compiling assignment expressions. |
- frame->EmitPush(r0); |
- |
- } else { |
- ASSERT(!slot->var()->is_dynamic()); |
- |
- JumpTarget exit; |
- if (init_state == CONST_INIT) { |
- ASSERT(slot->var()->mode() == Variable::CONST); |
- // Only the first const initialization must be executed (the slot |
- // still contains 'the hole' value). When the assignment is |
- // executed, the code is identical to a normal store (see below). |
- Comment cmnt(masm, "[ Init const"); |
- __ ldr(r2, cgen_->SlotOperand(slot, r2)); |
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
- __ cmp(r2, ip); |
- exit.Branch(ne); |
- } |
- |
- // We must execute the store. Storing a variable must keep the |
- // (new) value on the stack. This is necessary for compiling |
- // assignment expressions. |
- // |
- // Note: We will reach here even with slot->var()->mode() == |
- // Variable::CONST because of const declarations which will |
- // initialize consts to 'the hole' value and by doing so, end up |
- // calling this code. r2 may be loaded with context; used below in |
- // RecordWrite. |
- frame->EmitPop(r0); |
- __ str(r0, cgen_->SlotOperand(slot, r2)); |
- frame->EmitPush(r0); |
- if (slot->type() == Slot::CONTEXT) { |
- // Skip write barrier if the written value is a smi. |
- __ tst(r0, Operand(kSmiTagMask)); |
- exit.Branch(eq); |
- // r2 is loaded with context when calling SlotOperand above. |
- int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
- __ mov(r3, Operand(offset)); |
- __ RecordWrite(r2, r3, r1); |
- } |
- // If we definitely did not jump over the assignment, we do not need |
- // to bind the exit label. Doing so can defeat peephole |
- // optimization. |
- if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { |
- exit.Bind(); |
- } |
- } |
+ cgen_->StoreToSlot(slot, init_state); |
break; |
} |