Index: src/arm/codegen-arm.cc |
=================================================================== |
--- src/arm/codegen-arm.cc (revision 3775) |
+++ src/arm/codegen-arm.cc (working copy) |
@@ -143,7 +143,9 @@ |
// r1: called JS function |
// cp: callee's context |
-void CodeGenerator::GenCode(FunctionLiteral* fun, CompilationInfo* info) { |
+void CodeGenerator::Generate(FunctionLiteral* fun, |
+ Mode mode, |
+ CompilationInfo* info) { |
// Record the position for debugging purposes. |
CodeForFunctionPosition(fun); |
@@ -169,8 +171,7 @@ |
// r1: called JS function |
// cp: callee's context |
allocator_->Initialize(); |
- frame_->Enter(); |
- // tos: code slot |
+ |
#ifdef DEBUG |
if (strlen(FLAG_stop_at) > 0 && |
fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
@@ -179,104 +180,118 @@ |
} |
#endif |
- // Allocate space for locals and initialize them. This also checks |
- // for stack overflow. |
- frame_->AllocateStackSlots(); |
- // Initialize the function return target after the locals are set |
- // up, because it needs the expected frame height from the frame. |
- function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
- function_return_is_shadowed_ = false; |
+ if (mode == PRIMARY) { |
+ frame_->Enter(); |
+ // tos: code slot |
- VirtualFrame::SpilledScope spilled_scope; |
- int heap_slots = scope_->num_heap_slots(); |
- if (heap_slots > 0) { |
- // Allocate local context. |
- // Get outer context and create a new context based on it. |
- __ ldr(r0, frame_->Function()); |
- frame_->EmitPush(r0); |
- if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
- FastNewContextStub stub(heap_slots); |
- frame_->CallStub(&stub, 1); |
- } else { |
- frame_->CallRuntime(Runtime::kNewContext, 1); |
- } |
+ // Allocate space for locals and initialize them. This also checks |
+ // for stack overflow. |
+ frame_->AllocateStackSlots(); |
+ VirtualFrame::SpilledScope spilled_scope; |
+ int heap_slots = scope_->num_heap_slots(); |
+ if (heap_slots > 0) { |
+ // Allocate local context. |
+ // Get outer context and create a new context based on it. |
+ __ ldr(r0, frame_->Function()); |
+ frame_->EmitPush(r0); |
+ if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
+ FastNewContextStub stub(heap_slots); |
+ frame_->CallStub(&stub, 1); |
+ } else { |
+ frame_->CallRuntime(Runtime::kNewContext, 1); |
+ } |
+ |
#ifdef DEBUG |
- JumpTarget verified_true; |
- __ cmp(r0, Operand(cp)); |
- verified_true.Branch(eq); |
- __ stop("NewContext: r0 is expected to be the same as cp"); |
- verified_true.Bind(); |
+ JumpTarget verified_true; |
+ __ cmp(r0, Operand(cp)); |
+ verified_true.Branch(eq); |
+ __ stop("NewContext: r0 is expected to be the same as cp"); |
+ verified_true.Bind(); |
#endif |
- // Update context local. |
- __ str(cp, frame_->Context()); |
- } |
+ // Update context local. |
+ __ str(cp, frame_->Context()); |
+ } |
- // TODO(1241774): Improve this code: |
- // 1) only needed if we have a context |
- // 2) no need to recompute context ptr every single time |
- // 3) don't copy parameter operand code from SlotOperand! |
- { |
- Comment cmnt2(masm_, "[ copy context parameters into .context"); |
+ // TODO(1241774): Improve this code: |
+ // 1) only needed if we have a context |
+ // 2) no need to recompute context ptr every single time |
+ // 3) don't copy parameter operand code from SlotOperand! |
+ { |
+ Comment cmnt2(masm_, "[ copy context parameters into .context"); |
- // Note that iteration order is relevant here! If we have the same |
- // parameter twice (e.g., function (x, y, x)), and that parameter |
- // needs to be copied into the context, it must be the last argument |
- // passed to the parameter that needs to be copied. This is a rare |
- // case so we don't check for it, instead we rely on the copying |
- // order: such a parameter is copied repeatedly into the same |
- // context location and thus the last value is what is seen inside |
- // the function. |
- for (int i = 0; i < scope_->num_parameters(); i++) { |
- Variable* par = scope_->parameter(i); |
- Slot* slot = par->slot(); |
- if (slot != NULL && slot->type() == Slot::CONTEXT) { |
- ASSERT(!scope_->is_global_scope()); // no parameters in global scope |
- __ ldr(r1, frame_->ParameterAt(i)); |
- // Loads r2 with context; used below in RecordWrite. |
- __ str(r1, SlotOperand(slot, r2)); |
- // Load the offset into r3. |
- int slot_offset = |
- FixedArray::kHeaderSize + slot->index() * kPointerSize; |
- __ mov(r3, Operand(slot_offset)); |
- __ RecordWrite(r2, r3, r1); |
+ // Note that iteration order is relevant here! If we have the same |
+ // parameter twice (e.g., function (x, y, x)), and that parameter |
+ // needs to be copied into the context, it must be the last argument |
+ // passed to the parameter that needs to be copied. This is a rare |
+ // case so we don't check for it, instead we rely on the copying |
+ // order: such a parameter is copied repeatedly into the same |
+ // context location and thus the last value is what is seen inside |
+ // the function. |
+ for (int i = 0; i < scope_->num_parameters(); i++) { |
+ Variable* par = scope_->parameter(i); |
+ Slot* slot = par->slot(); |
+ if (slot != NULL && slot->type() == Slot::CONTEXT) { |
+ // No parameters in global scope. |
+ ASSERT(!scope_->is_global_scope()); |
+ __ ldr(r1, frame_->ParameterAt(i)); |
+ // Loads r2 with context; used below in RecordWrite. |
+ __ str(r1, SlotOperand(slot, r2)); |
+ // Load the offset into r3. |
+ int slot_offset = |
+ FixedArray::kHeaderSize + slot->index() * kPointerSize; |
+ __ mov(r3, Operand(slot_offset)); |
+ __ RecordWrite(r2, r3, r1); |
+ } |
} |
} |
- } |
- // Store the arguments object. This must happen after context |
- // initialization because the arguments object may be stored in the |
- // context. |
- if (scope_->arguments() != NULL) { |
- Comment cmnt(masm_, "[ allocate arguments object"); |
- ASSERT(scope_->arguments_shadow() != NULL); |
- Variable* arguments = scope_->arguments()->var(); |
- Variable* shadow = scope_->arguments_shadow()->var(); |
- ASSERT(arguments != NULL && arguments->slot() != NULL); |
- ASSERT(shadow != NULL && shadow->slot() != NULL); |
- ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
- __ ldr(r2, frame_->Function()); |
- // The receiver is below the arguments, the return address, and the |
- // frame pointer on the stack. |
- const int kReceiverDisplacement = 2 + scope_->num_parameters(); |
- __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); |
- __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
- frame_->Adjust(3); |
- __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); |
- frame_->CallStub(&stub, 3); |
- frame_->EmitPush(r0); |
- StoreToSlot(arguments->slot(), NOT_CONST_INIT); |
- StoreToSlot(shadow->slot(), NOT_CONST_INIT); |
- frame_->Drop(); // Value is no longer needed. |
- } |
+ // Store the arguments object. This must happen after context |
+ // initialization because the arguments object may be stored in the |
+ // context. |
+ if (scope_->arguments() != NULL) { |
+ Comment cmnt(masm_, "[ allocate arguments object"); |
+ ASSERT(scope_->arguments_shadow() != NULL); |
+ Variable* arguments = scope_->arguments()->var(); |
+ Variable* shadow = scope_->arguments_shadow()->var(); |
+ ASSERT(arguments != NULL && arguments->slot() != NULL); |
+ ASSERT(shadow != NULL && shadow->slot() != NULL); |
+ ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
+ __ ldr(r2, frame_->Function()); |
+ // The receiver is below the arguments, the return address, and the |
+ // frame pointer on the stack. |
+ const int kReceiverDisplacement = 2 + scope_->num_parameters(); |
+ __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); |
+ __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
+ frame_->Adjust(3); |
+ __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); |
+ frame_->CallStub(&stub, 3); |
+ frame_->EmitPush(r0); |
+ StoreToSlot(arguments->slot(), NOT_CONST_INIT); |
+ StoreToSlot(shadow->slot(), NOT_CONST_INIT); |
+ 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); |
+ // 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); |
+ } |
+ } else { |
+ // When used as the secondary compiler for splitting, r1, cp, |
+ // fp, and lr have been pushed on the stack. Adjust the virtual |
+ // frame to match this state. |
+ frame_->Adjust(4); |
+ allocator_->Unuse(r1); |
+ allocator_->Unuse(lr); |
} |
+ // Initialize the function return target after the locals are set |
+ // up, because it needs the expected frame height from the frame. |
+ function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
+ function_return_is_shadowed_ = false; |
+ |
// 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. |