Chromium Code Reviews| Index: src/arm/codegen-arm.cc |
| =================================================================== |
| --- src/arm/codegen-arm.cc (revision 4863) |
| +++ src/arm/codegen-arm.cc (working copy) |
| @@ -157,6 +157,7 @@ |
| state_(NULL), |
| loop_nesting_(0), |
| type_info_(NULL), |
| + function_return_(JumpTarget::BIDIRECTIONAL), |
| function_return_is_shadowed_(false) { |
| } |
| @@ -218,7 +219,7 @@ |
| // for stack overflow. |
| frame_->AllocateStackSlots(); |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| + frame_->AssertIsSpilled(); |
| int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| if (heap_slots > 0) { |
| // Allocate local context. |
| @@ -257,6 +258,7 @@ |
| // order: such a parameter is copied repeatedly into the same |
| // context location and thus the last value is what is seen inside |
| // the function. |
| + frame_->AssertIsSpilled(); |
| for (int i = 0; i < scope()->num_parameters(); i++) { |
| Variable* par = scope()->parameter(i); |
| Slot* slot = par->slot(); |
| @@ -283,8 +285,7 @@ |
| // Initialize ThisFunction reference if present. |
| if (scope()->is_function_scope() && scope()->function() != NULL) { |
| - __ mov(ip, Operand(Factory::the_hole_value())); |
| - frame_->EmitPush(ip); |
| + frame_->EmitPushRoot(Heap::kTheHoleValueRootIndex); |
| StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT); |
| } |
| } else { |
| @@ -511,7 +512,6 @@ |
| has_valid_frame() && |
| !has_cc() && |
| frame_->height() == original_height) { |
| - frame_->SpillAll(); |
| true_target->Jump(); |
| } |
| } |
| @@ -536,22 +536,19 @@ |
| if (has_cc()) { |
| // Convert cc_reg_ into a boolean value. |
| - VirtualFrame::SpilledScope scope(frame_); |
| JumpTarget loaded; |
| JumpTarget materialize_true; |
| materialize_true.Branch(cc_reg_); |
| __ LoadRoot(r0, Heap::kFalseValueRootIndex); |
| - frame_->EmitPush(r0); |
| + frame_->EmitPushRoot(Heap::kFalseValueRootIndex); |
| loaded.Jump(); |
| materialize_true.Bind(); |
| - __ LoadRoot(r0, Heap::kTrueValueRootIndex); |
| - frame_->EmitPush(r0); |
| + frame_->EmitPushRoot(Heap::kTrueValueRootIndex); |
| loaded.Bind(); |
| cc_reg_ = al; |
| } |
| if (true_target.is_linked() || false_target.is_linked()) { |
| - VirtualFrame::SpilledScope scope(frame_); |
| // We have at least one condition value that has been "translated" |
| // into a branch, thus it needs to be loaded explicitly. |
| JumpTarget loaded; |
| @@ -562,8 +559,7 @@ |
| // Load "true" if necessary. |
| if (true_target.is_linked()) { |
| true_target.Bind(); |
| - __ LoadRoot(r0, Heap::kTrueValueRootIndex); |
| - frame_->EmitPush(r0); |
| + frame_->EmitPushRoot(Heap::kTrueValueRootIndex); |
| } |
| // If both "true" and "false" need to be loaded jump across the code for |
| // "false". |
| @@ -573,8 +569,7 @@ |
| // Load "false" if necessary. |
| if (false_target.is_linked()) { |
| false_target.Bind(); |
| - __ LoadRoot(r0, Heap::kFalseValueRootIndex); |
| - frame_->EmitPush(r0); |
| + frame_->EmitPushRoot(Heap::kFalseValueRootIndex); |
| } |
| // A value is loaded on all paths reaching this point. |
| loaded.Bind(); |
| @@ -593,11 +588,11 @@ |
| void CodeGenerator::LoadGlobalReceiver(Register scratch) { |
|
Søren Thygesen Gjesse
2010/06/15 10:29:56
scratch is not used anymore.
|
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| - __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX)); |
| - __ ldr(scratch, |
| - FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset)); |
| - frame_->EmitPush(scratch); |
| + Register reg = frame_->GetTOSRegister(); |
| + __ ldr(reg, ContextOperand(cp, Context::GLOBAL_INDEX)); |
| + __ ldr(reg, |
| + FieldMemOperand(reg, GlobalObject::kGlobalReceiverOffset)); |
| + frame_->EmitPush(reg); |
| } |
| @@ -614,8 +609,6 @@ |
| void CodeGenerator::StoreArgumentsObject(bool initial) { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| - |
| ArgumentsAllocationMode mode = ArgumentsMode(); |
| ASSERT(mode != NO_ARGUMENTS_ALLOCATION); |
| @@ -624,9 +617,9 @@ |
| // When using lazy arguments allocation, we store the hole value |
| // as a sentinel indicating that the arguments object hasn't been |
| // allocated yet. |
| - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| - frame_->EmitPush(ip); |
| + frame_->EmitPushRoot(Heap::kTheHoleValueRootIndex); |
| } else { |
| + frame_->SpillAll(); |
| ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| __ ldr(r2, frame_->Function()); |
| // The receiver is below the arguments, the return address, and the |
| @@ -650,9 +643,9 @@ |
| // already been written to. This can happen if the a function |
| // has a local variable named 'arguments'. |
| LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); |
| - frame_->EmitPop(r0); |
| + Register arguments = frame_->PopToRegister(); |
| __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| - __ cmp(r0, ip); |
| + __ cmp(arguments, ip); |
| done.Branch(ne); |
| } |
| StoreToSlot(arguments->slot(), NOT_CONST_INIT); |
| @@ -755,36 +748,35 @@ |
| // may jump to 'false_target' in case the register converts to 'false'. |
| void CodeGenerator::ToBoolean(JumpTarget* true_target, |
| JumpTarget* false_target) { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| // Note: The generated code snippet does not change stack variables. |
| // Only the condition code should be set. |
| - frame_->EmitPop(r0); |
| + Register tos = frame_->PopToRegister(); |
| // Fast case checks |
| // Check if the value is 'false'. |
| __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| - __ cmp(r0, ip); |
| + __ cmp(tos, ip); |
| false_target->Branch(eq); |
| // Check if the value is 'true'. |
| __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| - __ cmp(r0, ip); |
| + __ cmp(tos, ip); |
| true_target->Branch(eq); |
| // Check if the value is 'undefined'. |
| __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| - __ cmp(r0, ip); |
| + __ cmp(tos, ip); |
| false_target->Branch(eq); |
| // Check if the value is a smi. |
| - __ cmp(r0, Operand(Smi::FromInt(0))); |
| + __ cmp(tos, Operand(Smi::FromInt(0))); |
| false_target->Branch(eq); |
| - __ tst(r0, Operand(kSmiTagMask)); |
| + __ tst(tos, Operand(kSmiTagMask)); |
| true_target->Branch(eq); |
| // Slow case: call the runtime. |
| - frame_->EmitPush(r0); |
| + frame_->EmitPush(tos); |
| frame_->CallRuntime(Runtime::kToBool, 1); |
| // Convert the result (r0) to a condition code. |
| __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| @@ -936,7 +928,15 @@ |
| }; |
| + |
| +// On entry the non-constant side of the binary operation is in tos_register_ |
|
Søren Thygesen Gjesse
2010/06/15 10:29:56
Doesn't tos contain the result of performing the o
|
| +// and the constant smi side is nowhere. The tos_register_ is not used by the |
| +// virtual frame. On exit the answer is in the tos_register_ and the virtual |
| +// frame is unchanged. |
| void DeferredInlineSmiOperation::Generate() { |
| + VirtualFrame copied_frame(*frame_state()->frame()); |
| + copied_frame.SpillAll(); |
| + |
| Register lhs = r1; |
| Register rhs = r0; |
| switch (op_) { |
| @@ -1020,11 +1020,17 @@ |
| GenericBinaryOpStub stub(op_, overwrite_mode_, lhs, rhs, value_); |
| __ CallStub(&stub); |
| + |
| // The generic stub returns its value in r0, but that's not |
| // necessarily what we want. We want whatever the inlined code |
| // expected, which is that the answer is in the same register as |
| // the operand was. |
| __ Move(tos_register_, r0); |
| + |
| + // The tos register was not in use for the virtual frame that we |
| + // came into this function with, so we can merge back to that frame |
| + // without trashing it. |
| + copied_frame.MergeTo(frame_state()->frame()); |
| } |
| @@ -1125,12 +1131,6 @@ |
| // We move the top of stack to a register (normally no move is invoved). |
| Register tos = frame_->PopToRegister(); |
| - // All other registers are spilled. The deferred code expects one argument |
| - // in a register and all other values are flushed to the stack. The |
| - // answer is returned in the same register that the top of stack argument was |
| - // in. |
| - frame_->SpillAll(); |
| - |
| switch (op) { |
| case Token::ADD: { |
| DeferredCode* deferred = |
| @@ -1449,8 +1449,6 @@ |
| void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
| CallFunctionFlags flags, |
| int position) { |
| - frame_->AssertIsSpilled(); |
| - |
| // Push the arguments ("left-to-right") on the stack. |
| int arg_count = args->length(); |
| for (int i = 0; i < arg_count; i++) { |
| @@ -1483,7 +1481,6 @@ |
| // stack, as receiver and arguments, and calls x. |
| // In the implementation comments, we call x the applicand |
| // and y the receiver. |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); |
| ASSERT(arguments->IsArguments()); |
| @@ -1501,6 +1498,15 @@ |
| Load(receiver); |
| LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); |
| + // At this point the top two stack elements are probably in registers |
| + // since they were just loaded. Ensure they are in regs and get the |
| + // regs. |
| + Register receiver_reg = frame_->Peek2(); |
| + Register arguments_reg = frame_->Peek(); |
| + |
| + // From now on the frame is spilled. |
| + frame_->SpillAll(); |
| + |
| // Emit the source position information after having loaded the |
| // receiver and the arguments. |
| CodeForSourcePosition(position); |
| @@ -1514,32 +1520,30 @@ |
| // already. If so, just use that instead of copying the arguments |
| // from the stack. This also deals with cases where a local variable |
| // named 'arguments' has been introduced. |
| - __ ldr(r0, MemOperand(sp, 0)); |
| - |
| - Label slow, done; |
| + JumpTarget slow; |
| + Label done; |
| __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| - __ cmp(ip, r0); |
| - __ b(ne, &slow); |
| + __ cmp(ip, arguments_reg); |
| + slow.Branch(ne); |
| Label build_args; |
| // Get rid of the arguments object probe. |
| frame_->Drop(); |
| // Stack now has 3 elements on it. |
| // Contents of stack at this point: |
| - // sp[0]: receiver |
| + // sp[0]: receiver - in the receiver_reg register. |
| // sp[1]: applicand.apply |
| // sp[2]: applicand. |
| // Check that the receiver really is a JavaScript object. |
| - __ ldr(r0, MemOperand(sp, 0)); |
| - __ BranchOnSmi(r0, &build_args); |
| + __ BranchOnSmi(receiver_reg, &build_args); |
| // We allow all JSObjects including JSFunctions. As long as |
| // JS_FUNCTION_TYPE is the last instance type and it is right |
| // after LAST_JS_OBJECT_TYPE, we do not have to check the upper |
| // bound. |
| ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); |
| ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); |
| - __ CompareObjectType(r0, r1, r2, FIRST_JS_OBJECT_TYPE); |
| + __ CompareObjectType(receiver_reg, r2, r3, FIRST_JS_OBJECT_TYPE); |
| __ b(lt, &build_args); |
| // Check that applicand.apply is Function.prototype.apply. |
| @@ -1628,7 +1632,7 @@ |
| StoreArgumentsObject(false); |
| // Stack and frame now have 4 elements. |
| - __ bind(&slow); |
| + slow.Bind(); |
| // Generic computation of x.apply(y, args) with no special optimization. |
| // Flip applicand.apply and applicand on the stack, so |
| @@ -1653,7 +1657,6 @@ |
| void CodeGenerator::Branch(bool if_true, JumpTarget* target) { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| ASSERT(has_cc()); |
| Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
| target->Branch(cc); |
| @@ -1662,7 +1665,7 @@ |
| void CodeGenerator::CheckStack() { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| + frame_->SpillAll(); |
| Comment cmnt(masm_, "[ check stack"); |
| __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
| // Put the lr setup instruction in the delay slot. kInstrSize is added to |
| @@ -1684,7 +1687,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| for (int i = 0; frame_ != NULL && i < statements->length(); i++) { |
| Visit(statements->at(i)); |
| } |
| @@ -1696,7 +1698,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ Block"); |
| CodeForStatementPosition(node); |
| node->break_target()->SetExpectedHeight(); |
| @@ -1714,7 +1715,6 @@ |
| frame_->EmitPush(Operand(pairs)); |
| frame_->EmitPush(Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
| // The result is discarded. |
| } |
| @@ -1755,7 +1755,6 @@ |
| frame_->EmitPush(Operand(0)); |
| } |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
| // Ignore the return value (declarations are statements). |
| @@ -1900,7 +1899,6 @@ |
| void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ ContinueStatement"); |
| CodeForStatementPosition(node); |
| node->target()->continue_target()->Jump(); |
| @@ -1908,7 +1906,6 @@ |
| void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ BreakStatement"); |
| CodeForStatementPosition(node); |
| node->target()->break_target()->Jump(); |
| @@ -1916,7 +1913,7 @@ |
| void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| + frame_->SpillAll(); |
| Comment cmnt(masm_, "[ ReturnStatement"); |
| CodeForStatementPosition(node); |
| @@ -1927,7 +1924,7 @@ |
| } else { |
| // Pop the result from the frame and prepare the frame for |
| // returning thus making it easier to merge. |
| - frame_->EmitPop(r0); |
| + frame_->PopToR0(); |
| frame_->PrepareForReturn(); |
| if (function_return_.is_bound()) { |
| // If the function return label is already bound we reuse the |
| @@ -1987,7 +1984,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ WithEnterStatement"); |
| CodeForStatementPosition(node); |
| Load(node->expression()); |
| @@ -2013,7 +2009,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ WithExitStatement"); |
| CodeForStatementPosition(node); |
| // Pop context. |
| @@ -2028,7 +2023,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ SwitchStatement"); |
| CodeForStatementPosition(node); |
| node->break_target()->SetExpectedHeight(); |
| @@ -2056,8 +2050,7 @@ |
| next_test.Bind(); |
| next_test.Unuse(); |
| // Duplicate TOS. |
| - __ ldr(r0, frame_->Top()); |
| - frame_->EmitPush(r0); |
| + frame_->Dup(); |
| Comparison(eq, NULL, clause->label(), true); |
| Branch(false, &next_test); |
| @@ -2095,7 +2088,7 @@ |
| default_entry.Bind(); |
| VisitStatements(default_clause->statements()); |
| // If control flow can fall out of the default and there is a case after |
| - // it, jup to that case's body. |
| + // it, jump to that case's body. |
| if (frame_ != NULL && default_exit.is_bound()) { |
| default_exit.Jump(); |
| } |
| @@ -2117,7 +2110,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ DoWhileStatement"); |
| CodeForStatementPosition(node); |
| node->break_target()->SetExpectedHeight(); |
| @@ -2192,7 +2184,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ WhileStatement"); |
| CodeForStatementPosition(node); |
| @@ -2210,7 +2201,7 @@ |
| node->continue_target()->Bind(); |
| if (info == DONT_KNOW) { |
| - JumpTarget body; |
| + JumpTarget body(JumpTarget::BIDIRECTIONAL); |
| LoadCondition(node->cond(), &body, node->break_target(), true); |
| if (has_valid_frame()) { |
| // A NULL frame indicates that control did not fall out of the |
| @@ -2243,7 +2234,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ ForStatement"); |
| CodeForStatementPosition(node); |
| if (node->init() != NULL) { |
| @@ -2932,7 +2922,6 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ Conditional"); |
| JumpTarget then; |
| JumpTarget else_; |
| @@ -2973,10 +2962,8 @@ |
| &done); |
| slow.Bind(); |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| frame_->EmitPush(cp); |
| - __ mov(r0, Operand(slot->var()->name())); |
| - frame_->EmitPush(r0); |
| + frame_->EmitPush(Operand(slot->var()->name())); |
| if (typeof_state == INSIDE_TYPEOF) { |
| frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| @@ -2991,16 +2978,17 @@ |
| Register scratch = VirtualFrame::scratch0(); |
| TypeInfo info = type_info(slot); |
| frame_->EmitPush(SlotOperand(slot, scratch), info); |
| + |
| if (slot->var()->mode() == Variable::CONST) { |
| // Const slots may contain 'the hole' value (the constant hasn't been |
| // initialized yet) which needs to be converted into the 'undefined' |
| // value. |
| Comment cmnt(masm_, "[ Unhole const"); |
| - frame_->EmitPop(scratch); |
| + Register tos = frame_->PopToRegister(); |
| __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| - __ cmp(scratch, ip); |
| - __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex, eq); |
| - frame_->EmitPush(scratch); |
| + __ cmp(tos, ip); |
| + __ LoadRoot(tos, Heap::kUndefinedValueRootIndex, eq); |
| + frame_->EmitPush(tos); |
| } |
| } |
| } |
| @@ -3008,6 +2996,7 @@ |
| void CodeGenerator::LoadFromSlotCheckForArguments(Slot* slot, |
| TypeofState state) { |
| + VirtualFrame::RegisterAllocationScope scope(this); |
| LoadFromSlot(slot, state); |
| // Bail out quickly if we're not using lazy arguments allocation. |
| @@ -3016,17 +3005,15 @@ |
| // ... or if the slot isn't a non-parameter arguments slot. |
| if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return; |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| - |
| - // Load the loaded value from the stack into r0 but leave it on the |
| + // Load the loaded value from the stack into a register but leave it on the |
| // stack. |
| - __ ldr(r0, MemOperand(sp, 0)); |
| + Register tos = frame_->Peek(); |
| // If the loaded value is the sentinel that indicates that we |
| // haven't loaded the arguments object yet, we need to do it now. |
| JumpTarget exit; |
| __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| - __ cmp(r0, ip); |
| + __ cmp(tos, ip); |
| exit.Branch(ne); |
| frame_->Drop(); |
| StoreArgumentsObject(false); |
| @@ -3036,14 +3023,13 @@ |
| void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
| ASSERT(slot != NULL); |
| + VirtualFrame::RegisterAllocationScope scope(this); |
| if (slot->type() == Slot::LOOKUP) { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| ASSERT(slot->var()->is_dynamic()); |
| // For now, just do a runtime call. |
| frame_->EmitPush(cp); |
| - __ mov(r0, Operand(slot->var()->name())); |
| - frame_->EmitPush(r0); |
| + frame_->EmitPush(Operand(slot->var()->name())); |
| if (init_state == CONST_INIT) { |
| // Same as the case for a normal store, but ignores attribute |
| @@ -3072,7 +3058,7 @@ |
| } else { |
| ASSERT(!slot->var()->is_dynamic()); |
| Register scratch = VirtualFrame::scratch0(); |
| - VirtualFrame::RegisterAllocationScope scope(this); |
| + Register scratch2 = VirtualFrame::scratch1(); |
| // The frame must be spilled when branching to this target. |
| JumpTarget exit; |
| @@ -3086,7 +3072,6 @@ |
| __ ldr(scratch, SlotOperand(slot, scratch)); |
| __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| __ cmp(scratch, ip); |
| - frame_->SpillAll(); |
| exit.Branch(ne); |
| } |
| @@ -3105,19 +3090,19 @@ |
| // Skip write barrier if the written value is a smi. |
| __ tst(tos, Operand(kSmiTagMask)); |
| // We don't use tos any more after here. |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| exit.Branch(eq); |
| // scratch is loaded with context when calling SlotOperand above. |
| int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
| - __ mov(r3, Operand(offset)); |
| - // r1 could be identical with tos, but that doesn't matter. |
| - __ RecordWrite(scratch, r3, r1); |
| + __ mov(scratch2, Operand(offset)); |
| + // We need an extra register. Until we have a way to do that in the |
| + // virtual frame we will cheat and ask for a free TOS register. |
| + Register scratch3 = frame_->GetTOSRegister(); |
| + __ RecordWrite(scratch, scratch2, scratch3); |
| } |
| // 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) { |
| - frame_->SpillAll(); |
| exit.Bind(); |
| } |
| } |
| @@ -3291,42 +3276,51 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ RexExp Literal"); |
| + Register tmp = VirtualFrame::scratch0(); |
| + // Free up a TOS register that can be used to push the literal. |
| + Register literal = frame_->GetTOSRegister(); |
| + |
| // Retrieve the literal array and check the allocated entry. |
| // Load the function of this activation. |
| - __ ldr(r1, frame_->Function()); |
| + __ ldr(tmp, frame_->Function()); |
| // Load the literals array of the function. |
| - __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
| + __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kLiteralsOffset)); |
| // Load the literal at the ast saved index. |
| int literal_offset = |
| FixedArray::kHeaderSize + node->literal_index() * kPointerSize; |
| - __ ldr(r2, FieldMemOperand(r1, literal_offset)); |
| + __ ldr(literal, FieldMemOperand(tmp, literal_offset)); |
| JumpTarget done; |
| __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| - __ cmp(r2, ip); |
| + __ cmp(literal, ip); |
| + // This branch locks the virtual frame at the done label to match the |
| + // one we have here, where the literal register is not on the stack and |
| + // nothing is spilled. |
| done.Branch(ne); |
| - // If the entry is undefined we call the runtime system to computed |
| + // If the entry is undefined we call the runtime system to compute |
| // the literal. |
| - frame_->EmitPush(r1); // literal array (0) |
| - __ mov(r0, Operand(Smi::FromInt(node->literal_index()))); |
| - frame_->EmitPush(r0); // literal index (1) |
| - __ mov(r0, Operand(node->pattern())); // RegExp pattern (2) |
| - frame_->EmitPush(r0); |
| - __ mov(r0, Operand(node->flags())); // RegExp flags (3) |
| - frame_->EmitPush(r0); |
| + // literal array (0) |
| + frame_->EmitPush(tmp); |
| + // literal index (1) |
| + frame_->EmitPush(Operand(Smi::FromInt(node->literal_index()))); |
| + // RegExp pattern (2) |
| + frame_->EmitPush(Operand(node->pattern())); |
| + // RegExp flags (3) |
| + frame_->EmitPush(Operand(node->flags())); |
| frame_->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| - __ mov(r2, Operand(r0)); |
| + __ Move(literal, r0); |
| + // This call to bind will get us back to the virtual frame we had before |
| + // where things are not spilled and the literal register is not on the stack. |
| done.Bind(); |
| // Push the literal. |
| - frame_->EmitPush(r2); |
| + frame_->EmitPush(literal); |
| ASSERT_EQ(original_height + 1, frame_->height()); |
| } |
| @@ -3335,20 +3329,20 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ ObjectLiteral"); |
| + Register literal = frame_->GetTOSRegister(); |
| // Load the function of this activation. |
| - __ ldr(r3, frame_->Function()); |
| + __ ldr(literal, frame_->Function()); |
| // Literal array. |
| - __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); |
| + __ ldr(literal, FieldMemOperand(literal, JSFunction::kLiteralsOffset)); |
| + frame_->EmitPush(literal); |
| // Literal index. |
| - __ mov(r2, Operand(Smi::FromInt(node->literal_index()))); |
| + frame_->EmitPush(Operand(Smi::FromInt(node->literal_index()))); |
| // Constant properties. |
| - __ mov(r1, Operand(node->constant_properties())); |
| + frame_->EmitPush(Operand(node->constant_properties())); |
| // Should the object literal have fast elements? |
| - __ mov(r0, Operand(Smi::FromInt(node->fast_elements() ? 1 : 0))); |
| - frame_->EmitPushMultiple(4, r3.bit() | r2.bit() | r1.bit() | r0.bit()); |
| + frame_->EmitPush(Operand(Smi::FromInt(node->fast_elements() ? 1 : 0))); |
| if (node->depth() > 1) { |
| frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4); |
| } else { |
| @@ -3371,37 +3365,33 @@ |
| if (key->handle()->IsSymbol()) { |
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| Load(value); |
| - frame_->EmitPop(r0); |
| + frame_->PopToR0(); |
| + // Fetch the object literal. |
| + frame_->SpillAllButCopyTOSToR1(); |
| __ mov(r2, Operand(key->handle())); |
| - __ ldr(r1, frame_->Top()); // Load the receiver. |
| frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
| break; |
| } |
| // else fall through |
| case ObjectLiteral::Property::PROTOTYPE: { |
| - __ ldr(r0, frame_->Top()); |
| - frame_->EmitPush(r0); // dup the result |
| + frame_->Dup(); |
| Load(key); |
| Load(value); |
| frame_->CallRuntime(Runtime::kSetProperty, 3); |
| break; |
| } |
| case ObjectLiteral::Property::SETTER: { |
| - __ ldr(r0, frame_->Top()); |
| - frame_->EmitPush(r0); |
| + frame_->Dup(); |
| Load(key); |
| - __ mov(r0, Operand(Smi::FromInt(1))); |
| - frame_->EmitPush(r0); |
| + frame_->EmitPush(Operand(Smi::FromInt(1))); |
| Load(value); |
| frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| break; |
| } |
| case ObjectLiteral::Property::GETTER: { |
| - __ ldr(r0, frame_->Top()); |
| - frame_->EmitPush(r0); |
| + frame_->Dup(); |
| Load(key); |
| - __ mov(r0, Operand(Smi::FromInt(0))); |
| - frame_->EmitPush(r0); |
| + frame_->EmitPush(Operand(Smi::FromInt(0))); |
| Load(value); |
| frame_->CallRuntime(Runtime::kDefineAccessor, 4); |
| break; |
| @@ -3416,16 +3406,16 @@ |
| #ifdef DEBUG |
| int original_height = frame_->height(); |
| #endif |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| Comment cmnt(masm_, "[ ArrayLiteral"); |
| + Register tos = frame_->GetTOSRegister(); |
| // Load the function of this activation. |
| - __ ldr(r2, frame_->Function()); |
| + __ ldr(tos, frame_->Function()); |
| // Load the literals array of the function. |
| - __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); |
| - __ mov(r1, Operand(Smi::FromInt(node->literal_index()))); |
| - __ mov(r0, Operand(node->constant_elements())); |
| - frame_->EmitPushMultiple(3, r2.bit() | r1.bit() | r0.bit()); |
| + __ ldr(tos, FieldMemOperand(tos, JSFunction::kLiteralsOffset)); |
| + frame_->EmitPush(tos); |
| + frame_->EmitPush(Operand(Smi::FromInt(node->literal_index()))); |
| + frame_->EmitPush(Operand(node->constant_elements())); |
| int length = node->values()->length(); |
| if (node->depth() > 1) { |
| frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); |
| @@ -3452,10 +3442,10 @@ |
| // The property must be set by generated code. |
| Load(value); |
| - frame_->EmitPop(r0); |
| - |
| + frame_->PopToR0(); |
| // Fetch the object literal. |
| - __ ldr(r1, frame_->Top()); |
| + frame_->SpillAllButCopyTOSToR1(); |
| + |
| // Get the elements array. |
| __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); |
| @@ -3866,7 +3856,6 @@ |
| // ------------------------------------------------------------------------ |
| if (var != NULL && var->is_possibly_eval()) { |
| - VirtualFrame::SpilledScope spilled_scope(frame_); |
| // ---------------------------------- |
| // JavaScript example: 'eval(arg)' // eval is not known to be shadowed |
| // ---------------------------------- |
| @@ -3880,8 +3869,7 @@ |
| Load(function); |
| // Allocate a frame slot for the receiver. |
| - __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); |
| - frame_->EmitPush(r2); |
| + frame_->EmitPushRoot(Heap::kUndefinedValueRootIndex); |
| // Load the arguments. |
| int arg_count = args->length(); |
| @@ -3889,6 +3877,8 @@ |
| Load(args->at(i)); |
| } |
| + VirtualFrame::SpilledScope spilled_scope(frame_); |
| + |
| // If we know that eval can only be shadowed by eval-introduced |
| // variables we attempt to load the global eval function directly |
| // in generated code. If we succeed, there is no need to perform a |