Chromium Code Reviews| Index: src/codegen-arm.cc |
| =================================================================== |
| --- src/codegen-arm.cc (revision 703) |
| +++ src/codegen-arm.cc (working copy) |
| @@ -49,6 +49,72 @@ |
| } |
| +void VirtualFrame::Enter() { |
| + Comment cmnt(masm_, "[ Enter JS frame"); |
| +#ifdef DEBUG |
| + { Label done, fail; |
| + __ tst(r1, Operand(kSmiTagMask)); |
| + __ b(eq, &fail); |
| + __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| + __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| + __ cmp(r2, Operand(JS_FUNCTION_TYPE)); |
| + __ b(eq, &done); |
| + __ bind(&fail); |
| + __ stop("CodeGenerator::EnterJSFrame - r1 not a function"); |
| + __ bind(&done); |
| + } |
| +#endif // DEBUG |
| + |
| + __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| + // Adjust FP to point to saved FP. |
| + __ add(fp, sp, Operand(2 * kPointerSize)); |
| +} |
| + |
| + |
| +void VirtualFrame::Exit() { |
| + Comment cmnt(masm_, "[ Exit JS frame"); |
| + // Drop the execution stack down to the frame pointer and restore the caller |
| + // frame pointer and return address. |
| + __ mov(sp, fp); |
| + __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| +} |
| + |
| + |
| +void VirtualFrame::AllocateLocals() { |
| + if (frame_local_count_ > 0) { |
| + Comment cmnt(masm_, "[ Allocate space for locals"); |
| + // Initialize stack slots with 'undefined' value. |
| + __ mov(ip, Operand(Factory::undefined_value())); |
| + for (int i = 0; i < frame_local_count_; i++) { |
| + __ push(ip); |
| + } |
| + } |
| +} |
| + |
| + |
| +void VirtualFrame::Drop(int count) { |
| + ASSERT(count >= 0); |
| + if (count > 0) { |
| + __ add(sp, sp, Operand(count * kPointerSize)); |
| + } |
| +} |
| + |
| + |
| +void VirtualFrame::Pop() { |
| + __ add(sp, sp, Operand(kPointerSize)); |
|
iposva
2008/11/06 18:18:34
Shouldn't this just call Drop(1)?
Kevin Millikin (Chromium)
2008/11/07 08:19:10
Fixed.
|
| +} |
| + |
| + |
| +void VirtualFrame::Pop(Register reg) { |
| + __ pop(reg); |
| +} |
| + |
| + |
| +void VirtualFrame::Push(Register reg) { |
| + __ push(reg); |
| +} |
| + |
| + |
| // ------------------------------------------------------------------------- |
| // CodeGenState implementation. |
| @@ -99,7 +165,6 @@ |
| // Calling conventions: |
| - |
| // r0: the number of arguments |
| // fp: frame pointer |
| // sp: stack pointer |
| @@ -127,9 +192,7 @@ |
| // pp: caller's parameter pointer |
| // cp: callee's context |
|
iposva
2008/11/06 18:18:34
ditto
|
| - { Comment cmnt(masm_, "[ enter JS frame"); |
| - EnterJSFrame(); |
| - } |
| + frame_->Enter(); |
| // tos: code slot |
| #ifdef DEBUG |
| if (strlen(FLAG_stop_at) > 0 && |
| @@ -139,20 +202,13 @@ |
| #endif |
| // Allocate space for locals and initialize them. |
| - if (scope_->num_stack_slots() > 0) { |
| - Comment cmnt(masm_, "[ allocate space for locals"); |
| - // Initialize stack slots with 'undefined' value. |
| - __ mov(ip, Operand(Factory::undefined_value())); |
| - for (int i = 0; i < scope_->num_stack_slots(); i++) { |
| - __ push(ip); |
| - } |
| - } |
| + frame_->AllocateLocals(); |
| if (scope_->num_heap_slots() > 0) { |
| // Allocate local context. |
| // Get outer context and create a new context based on it. |
| __ ldr(r0, frame_->Function()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result |
| if (kDebug) { |
| @@ -166,7 +222,7 @@ |
| __ str(cp, frame_->Context()); |
| } |
| - // TODO(1241774): Improve this code!!! |
| + // 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! |
| @@ -198,9 +254,9 @@ |
| } |
| } |
| - // Store the arguments object. |
| - // This must happen after context initialization because |
| - // the arguments array may be stored in the context! |
| + // Store the arguments object. This must happen after context |
| + // initialization because the arguments object may be stored in the |
| + // context. |
| if (scope_->arguments() != NULL) { |
| ASSERT(scope_->arguments_shadow() != NULL); |
| Comment cmnt(masm_, "[ allocate arguments object"); |
| @@ -215,35 +271,31 @@ |
| __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
| __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); |
| __ CallStub(&stub); |
| - __ push(r0); |
| + frame_->Push(r0); |
| arguments_ref.SetValue(NOT_CONST_INIT); |
| } |
| shadow_ref.SetValue(NOT_CONST_INIT); |
| } |
| - __ pop(r0); // Value is no longer needed. |
| + frame_->Pop(); // Value is no longer needed. |
| } |
| - // 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. |
| + // 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. |
| if (scope_->HasIllegalRedeclaration()) { |
| Comment cmnt(masm_, "[ illegal redeclarations"); |
| scope_->VisitIllegalRedeclaration(this); |
| } else { |
| Comment cmnt(masm_, "[ declarations"); |
| - // ProcessDeclarations calls DeclareGlobals indirectly |
| ProcessDeclarations(scope_->declarations()); |
| - |
| - // Bail out if a stack-overflow exception occurred when |
| - // processing declarations. |
| + // Bail out if a stack-overflow exception occurred when processing |
| + // declarations. |
| if (HasStackOverflow()) return; |
| } |
| if (FLAG_trace) { |
| - // Push a valid value as the parameter. The runtime call only uses |
| - // it as the return value to indicate non-failure. |
| __ CallRuntime(Runtime::kTraceEnter, 0); |
| + // Ignore the return value. |
| } |
| CheckStack(); |
| @@ -258,6 +310,7 @@ |
| is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; |
| if (should_trace) { |
| __ CallRuntime(Runtime::kDebugTrace, 0); |
| + // Ignore the return value. |
| } |
| #endif |
| VisitStatements(body); |
| @@ -276,13 +329,13 @@ |
| if (FLAG_trace) { |
| // Push the return value on the stack as the parameter. |
| // Runtime::TraceExit returns the parameter as it is. |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kTraceExit, 1); |
| } |
| // Tear down the frame which will restore the caller's frame pointer and the |
| // link register. |
| - ExitJSFrame(); |
| + frame_->Exit(); |
| __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize)); |
| __ mov(pc, lr); |
| @@ -346,16 +399,17 @@ |
| } |
| -// Loads a value on the stack. If it is a boolean value, the result may have |
| -// been (partially) translated into branches, or it may have set the condition |
| -// code register. If force_cc is set, the value is forced to set the condition |
| -// code register and no value is pushed. If the condition code register was set, |
| -// has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
| +// Loads a value on TOS. If it is a boolean value, the result may have been |
| +// (partially) translated into branches, or it may have set the condition |
| +// code register. If force_cc is set, the value is forced to set the |
| +// condition code register and no value is pushed. If the condition code |
| +// register was set, has_cc() is true and cc_reg_ contains the condition to |
| +// test for 'true'. |
| void CodeGenerator::LoadCondition(Expression* x, |
| - TypeofState typeof_state, |
| - Label* true_target, |
| - Label* false_target, |
| - bool force_cc) { |
| + TypeofState typeof_state, |
| + Label* true_target, |
| + Label* false_target, |
| + bool force_cc) { |
| ASSERT(!has_cc()); |
| { CodeGenState new_state(this, typeof_state, true_target, false_target); |
| @@ -363,6 +417,13 @@ |
| } |
| if (force_cc && !has_cc()) { |
| // Convert the TOS value to a boolean in the condition code register. |
| + // Visiting an expression may possibly choose neither (a) to leave a |
| + // value in the condition code register nor (b) to leave a value in TOS |
| + // (eg, by compiling to only jumps to the targets). In that case the |
| + // code generated by ToBoolean is wrong because it assumes the value of |
| + // the expression in TOS. So long as there is always a value in TOS or |
| + // the condition code register when control falls through to here (there |
| + // is), the code generated by ToBoolean is dead and therefore safe. |
| ToBoolean(true_target, false_target); |
| } |
| ASSERT(has_cc() || !force_cc); |
| @@ -379,11 +440,11 @@ |
| Label loaded, materialize_true; |
| __ b(cc_reg_, &materialize_true); |
| __ mov(r0, Operand(Factory::false_value())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ b(&loaded); |
| __ bind(&materialize_true); |
| __ mov(r0, Operand(Factory::true_value())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ bind(&loaded); |
| cc_reg_ = al; |
| } |
| @@ -399,7 +460,7 @@ |
| if (true_target.is_linked()) { |
| __ bind(&true_target); |
| __ mov(r0, Operand(Factory::true_value())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| // if both "true" and "false" need to be reincarnated, |
| // jump across code for "false" |
| @@ -409,7 +470,7 @@ |
| if (false_target.is_linked()) { |
| __ bind(&false_target); |
| __ mov(r0, Operand(Factory::false_value())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| // everything is loaded at this point |
| __ bind(&loaded); |
| @@ -420,14 +481,15 @@ |
| void CodeGenerator::LoadGlobal() { |
| __ ldr(r0, GlobalObject()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| -void CodeGenerator::LoadGlobalReceiver(Register s) { |
| - __ ldr(s, ContextOperand(cp, Context::GLOBAL_INDEX)); |
| - __ ldr(s, FieldMemOperand(s, GlobalObject::kGlobalReceiverOffset)); |
| - __ push(s); |
| +void CodeGenerator::LoadGlobalReceiver(Register scratch) { |
| + __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX)); |
| + __ ldr(scratch, |
| + FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset)); |
| + frame_->Push(scratch); |
| } |
| @@ -465,7 +527,6 @@ |
| void CodeGenerator::LoadReference(Reference* ref) { |
| Comment cmnt(masm_, "[ LoadReference"); |
| - |
| Expression* e = ref->expression(); |
| Property* property = e->AsProperty(); |
| Variable* var = e->AsVariableProxy()->AsVariable(); |
| @@ -507,15 +568,15 @@ |
| void CodeGenerator::UnloadReference(Reference* ref) { |
| + // Pop a reference from the stack while preserving TOS. |
| Comment cmnt(masm_, "[ UnloadReference"); |
| - |
| int size = ref->size(); |
| if (size <= 0) { |
|
iposva
2008/11/06 18:18:34
Can a reference size ever be negative? If not, the
Kevin Millikin (Chromium)
2008/11/07 08:19:10
Yes it can be negative, but we should probably cha
|
| // Do nothing. No popping is necessary. |
| } else { |
| - __ pop(r0); |
| - __ add(sp, sp, Operand(size * kPointerSize)); |
| - __ push(r0); |
| + frame_->Pop(r0); |
| + frame_->Drop(size); |
| + frame_->Push(r0); |
| } |
| } |
| @@ -524,10 +585,10 @@ |
| // register to a boolean in the condition code register. The code |
| // may jump to 'false_target' in case the register converts to 'false'. |
| void CodeGenerator::ToBoolean(Label* true_target, |
| - Label* false_target) { |
| + Label* false_target) { |
| // Note: The generated code snippet does not change stack variables. |
| // Only the condition code should be set. |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| // Fast case checks |
| @@ -550,10 +611,9 @@ |
| __ b(eq, true_target); |
| // Slow case: call the runtime. |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kToBool, 1); |
| - |
| - // Convert result (r0) to condition code |
| + // Convert the result (r0) to a condition code. |
| __ cmp(r0, Operand(Factory::false_value())); |
| cc_reg_ = ne; |
| @@ -654,8 +714,8 @@ |
| case Token::SHL: |
| case Token::SHR: |
| case Token::SAR: { |
| - __ pop(r0); // r0 : y |
| - __ pop(r1); // r1 : x |
| + frame_->Pop(r0); // r0 : y |
| + frame_->Pop(r1); // r1 : x |
| GenericBinaryOpStub stub(op); |
| __ CallStub(&stub); |
| break; |
| @@ -674,9 +734,9 @@ |
| } |
| case Token::COMMA: |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| // simply discard left value |
| - __ pop(); |
| + frame_->Pop(); |
| break; |
| default: |
| @@ -764,8 +824,8 @@ |
| void CodeGenerator::SmiOperation(Token::Value op, |
| - Handle<Object> value, |
| - bool reversed) { |
| + Handle<Object> value, |
| + bool reversed) { |
| // NOTE: This is an attempt to inline (a bit) more of the code for |
| // some possible smi operations (like + and -) when (at least) one |
| // of the operands is a literal smi. With this optimization, the |
| @@ -778,7 +838,7 @@ |
| int int_value = Smi::cast(*value)->value(); |
| Label exit; |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| switch (op) { |
| case Token::ADD: { |
| @@ -831,8 +891,8 @@ |
| case Token::SAR: { |
| if (reversed) { |
| __ mov(ip, Operand(value)); |
| - __ push(ip); |
| - __ push(r0); |
| + frame_->Push(ip); |
| + frame_->Push(r0); |
| GenericBinaryOperation(op); |
| } else { |
| @@ -882,13 +942,13 @@ |
| default: |
| if (!reversed) { |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(value)); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } else { |
| __ mov(ip, Operand(value)); |
| - __ push(ip); |
| - __ push(r0); |
| + frame_->Push(ip); |
| + frame_->Push(r0); |
| } |
| GenericBinaryOperation(op); |
| break; |
| @@ -910,18 +970,18 @@ |
| // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
| if (cc == gt || cc == le) { |
| cc = ReverseCondition(cc); |
| - __ pop(r1); |
| - __ pop(r0); |
| + frame_->Pop(r1); |
| + frame_->Pop(r0); |
| } else { |
| - __ pop(r0); |
| - __ pop(r1); |
| + frame_->Pop(r0); |
| + frame_->Pop(r1); |
| } |
| __ orr(r2, r0, Operand(r1)); |
| __ tst(r2, Operand(kSmiTagMask)); |
| __ b(eq, &smi); |
| // Perform non-smi comparison by runtime call. |
| - __ push(r1); |
| + frame_->Push(r1); |
| // Figure out which native to call and setup the arguments. |
| Builtins::JavaScript native; |
| @@ -938,14 +998,14 @@ |
| ASSERT(cc == gt || cc == ge); // remaining cases |
| ncr = LESS; |
| } |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(Smi::FromInt(ncr))); |
| argc = 2; |
| } |
| // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) |
| // tagged as a small integer. |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(argc)); |
| __ InvokeBuiltin(native, CALL_JS); |
| __ cmp(r0, Operand(0)); |
| @@ -995,7 +1055,7 @@ |
| // Restore context and pop function from the stack. |
| __ ldr(cp, frame_->Context()); |
| - __ pop(); // discard the TOS |
| + frame_->Pop(); // discard the TOS |
| } |
| @@ -1027,10 +1087,10 @@ |
| void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| __ mov(r0, Operand(pairs)); |
| - __ push(r0); |
| - __ push(cp); |
| + frame_->Push(r0); |
| + frame_->Push(cp); |
| __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kDeclareGlobals, 3); |
| // The result is discarded. |
| } |
| @@ -1050,26 +1110,26 @@ |
| // during variable resolution and must have mode DYNAMIC. |
| ASSERT(var->mode() == Variable::DYNAMIC); |
| // For now, just do a runtime call. |
| - __ push(cp); |
| + frame_->Push(cp); |
| __ mov(r0, Operand(var->name())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Declaration nodes are always declared in only two modes. |
| ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
| PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
| __ mov(r0, Operand(Smi::FromInt(attr))); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Push initial value, if any. |
| // Note: For variables we must not push an initial value (such as |
| // 'undefined') because we may have a (legal) redeclaration and we |
| // must not destroy the current value. |
| if (node->mode() == Variable::CONST) { |
| __ mov(r0, Operand(Factory::the_hole_value())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } else if (node->fun() != NULL) { |
| Load(node->fun()); |
| } else { |
| __ mov(r0, Operand(0)); // no initial value! |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
| // Ignore the return value (declarations are statements). |
| @@ -1096,7 +1156,7 @@ |
| // safe to pop the value lying on top of the reference before unloading |
| // the reference itself (which preserves the top of stack) because we |
| // know it is a zero-sized reference. |
| - __ pop(); |
| + frame_->Pop(); |
| } |
| } |
| @@ -1107,7 +1167,7 @@ |
| Expression* expression = node->expression(); |
| expression->MarkAsStatement(); |
| Load(expression); |
| - __ pop(); |
| + frame_->Pop(); |
| } |
| @@ -1172,7 +1232,7 @@ |
| if (has_cc()) { |
| cc_reg_ = al; |
| } else { |
| - __ pop(r0); // __ Pop(no_reg) |
| + frame_->Pop(); |
| } |
| } |
| @@ -1182,10 +1242,8 @@ |
| void CodeGenerator::CleanStack(int num_bytes) { |
| - ASSERT(num_bytes >= 0); |
| - if (num_bytes > 0) { |
| - __ add(sp, sp, Operand(num_bytes)); |
| - } |
| + ASSERT(num_bytes % kPointerSize == 0); |
| + frame_->Drop(num_bytes / kPointerSize); |
| } |
| @@ -1210,7 +1268,7 @@ |
| if (FLAG_debug_info) RecordStatementPosition(node); |
| Load(node->expression()); |
| // Move the function result into r0. |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| __ b(&function_return_); |
| } |
| @@ -1261,7 +1319,7 @@ |
| ASSERT(kSmiTag == 0 && kSmiTagSize <= 2); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| // Test for a Smi value in a HeapNumber. |
| Label is_smi; |
| @@ -1271,7 +1329,7 @@ |
| __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag)); |
| __ cmp(r1, Operand(HEAP_NUMBER_TYPE)); |
| __ b(ne, fail_label); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kNumberToSmi, 1); |
| __ bind(&is_smi); |
| @@ -1340,7 +1398,7 @@ |
| __ bind(&next); |
| next.Unuse(); |
| __ ldr(r0, frame_->Top()); |
| - __ push(r0); // duplicate TOS |
| + frame_->Push(r0); // duplicate TOS |
| Load(clause->label()); |
| Comparison(eq, true); |
| Branch(false, &next); |
| @@ -1348,7 +1406,7 @@ |
| // Entering the case statement for the first time. Remove the switch value |
| // from the stack. |
| - __ pop(r0); |
| + frame_->Pop(); |
| // Generate code for the body. |
| // This is also the target for the fall through from the previous case's |
| @@ -1367,7 +1425,7 @@ |
| __ b(&default_case); |
| } else { |
| // Remove the switch value from the stack. |
| - __ pop(r0); |
| + frame_->Pop(); |
| } |
| __ bind(&fall_through); |
| @@ -1463,7 +1521,7 @@ |
| // Get the object to enumerate over (converted to JSObject). |
| Load(node->enumerable()); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| // Both SpiderMonkey and kjs ignore null and undefined in contrast |
| // to the specification. 12.6.4 mandates a call to ToObject. |
| @@ -1488,7 +1546,7 @@ |
| __ b(hs, &jsobject); |
| __ bind(&primitive); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(0)); |
| __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); |
| @@ -1496,8 +1554,8 @@ |
| __ bind(&jsobject); |
| // Get the set of properties (as a FixedArray or Map). |
| - __ push(r0); // duplicate the object being enumerated |
| - __ push(r0); |
| + frame_->Push(r0); // duplicate the object being enumerated |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| // If we got a Map, we can do a fast modification check. |
| @@ -1514,28 +1572,28 @@ |
| __ ldr(r2, |
| FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| - __ push(r0); // map |
| - __ push(r2); // enum cache bridge cache |
| + frame_->Push(r0); // map |
| + frame_->Push(r2); // enum cache bridge cache |
| __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset)); |
| __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(Smi::FromInt(0))); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ b(&entry); |
| __ bind(&fixed_array); |
| __ mov(r1, Operand(Smi::FromInt(0))); |
| - __ push(r1); // insert 0 in place of Map |
| - __ push(r0); |
| + frame_->Push(r1); // insert 0 in place of Map |
| + frame_->Push(r0); |
| // Push the length of the array and the initial index onto the stack. |
| __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset)); |
| __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(Smi::FromInt(0))); // init index |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ b(&entry); |
| @@ -1546,9 +1604,9 @@ |
| // Next. |
| __ bind(node->continue_target()); |
| __ bind(&next); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| __ add(r0, r0, Operand(Smi::FromInt(1))); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Condition. |
| __ bind(&entry); |
| @@ -1581,8 +1639,8 @@ |
| // Convert the entry to a string (or null if it isn't a property anymore). |
| __ ldr(r0, frame_->Element(4)); // push enumerable |
| - __ push(r0); |
| - __ push(r3); // push entry |
| + frame_->Push(r0); |
| + frame_->Push(r3); // push entry |
| __ mov(r0, Operand(1)); |
| __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS); |
| __ mov(r3, Operand(r0)); |
| @@ -1596,12 +1654,12 @@ |
| // Store the entry in the 'each' expression and take another spin in the loop. |
| // r3: i'th entry of the enum cache (or string there of) |
| - __ push(r3); // push entry |
| + frame_->Push(r3); // push entry |
| { Reference each(this, node->each()); |
| if (!each.is_illegal()) { |
| if (each.size() > 0) { |
| __ ldr(r0, frame_->Element(each.size())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| // If the reference was to a slot we rely on the convenient property |
| // that it doesn't matter whether a value (eg, r3 pushed above) is |
| @@ -1613,20 +1671,20 @@ |
| // ie, now the topmost value of the non-zero sized reference), since |
| // we will discard the top of stack after unloading the reference |
| // anyway. |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| } |
| } |
| } |
| // Discard the i'th entry pushed above or else the remainder of the |
| // reference, whichever is currently on top of the stack. |
| - __ pop(); |
| + frame_->Pop(); |
| CheckStack(); // TODO(1222600): ignore if body contains calls. |
| __ jmp(&loop); |
| // Cleanup. |
| __ bind(&cleanup); |
| __ bind(node->break_target()); |
| - __ add(sp, sp, Operand(5 * kPointerSize)); |
| + frame_->Drop(5); |
| // Exit. |
| __ bind(&exit); |
| @@ -1641,11 +1699,10 @@ |
| Label try_block, exit; |
| __ bl(&try_block); |
| - |
| // --- Catch block --- |
| + frame_->Push(r0); |
| // Store the caught exception in the catch variable. |
| - __ push(r0); |
| { Reference ref(this, node->catch_var()); |
| ASSERT(ref.is_slot()); |
| // Here we make use of the convenient property that it doesn't matter |
| @@ -1655,7 +1712,7 @@ |
| } |
| // Remove the exception from the stack. |
| - __ pop(); |
| + frame_->Pop(); |
| VisitStatements(node->catch_block()->statements()); |
| __ b(&exit); |
| @@ -1682,7 +1739,7 @@ |
| // Generate code for the statements in the try block. |
| VisitStatements(node->try_block()->statements()); |
| - __ pop(r0); // Discard the result. |
| + frame_->Pop(); // Discard the result. |
| // Stop the introduced shadowing and count the number of required unlinks. |
| // After shadowing stops, the original labels are unshadowed and the |
| @@ -1702,7 +1759,7 @@ |
| __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| __ str(r1, MemOperand(r3)); |
| ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| - __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
| + frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| // Code slot popped. |
| if (nof_unlinks > 0) __ b(&exit); |
| @@ -1721,7 +1778,7 @@ |
| __ ldr(r1, frame_->Element(kNextIndex)); |
| __ str(r1, MemOperand(r3)); |
| ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| - __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
| + frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| // Code slot popped. |
| __ b(shadows[i]->original_label()); |
| @@ -1744,7 +1801,7 @@ |
| __ bl(&try_block); |
| - __ push(r0); // save exception object on the stack |
| + frame_->Push(r0); // save exception object on the stack |
| // In case of thrown exceptions, this is where we continue. |
| __ mov(r2, Operand(Smi::FromInt(THROWING))); |
| __ b(&finally_block); |
| @@ -1782,7 +1839,7 @@ |
| // Set the state on the stack to FALLING. |
| __ mov(r0, Operand(Factory::undefined_value())); // fake TOS |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r2, Operand(Smi::FromInt(FALLING))); |
| if (nof_unlinks > 0) __ b(&unlink); |
| @@ -1794,11 +1851,11 @@ |
| if (shadows[i]->original_label() == &function_return_) { |
| // If this label shadowed the function return, materialize the |
| // return value on the stack. |
| - __ push(r0); |
| + frame_->Push(r0); |
| } else { |
| // Fake TOS for labels that shadowed breaks and continues. |
| __ mov(r0, Operand(Factory::undefined_value())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| __ mov(r2, Operand(Smi::FromInt(JUMPING + i))); |
| __ b(&unlink); |
| @@ -1808,7 +1865,7 @@ |
| // Unlink from try chain; |
| __ bind(&unlink); |
| - __ pop(r0); // Store TOS in r0 across stack manipulation |
| + frame_->Pop(r0); // Store TOS in r0 across stack manipulation |
| // Reload sp from the top handler, because some statements that we |
| // break from (eg, for...in) may have left stuff on the stack. |
| __ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
| @@ -1819,15 +1876,15 @@ |
| __ ldr(r1, frame_->Element(kNextIndex)); |
| __ str(r1, MemOperand(r3)); |
| ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
| - __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
| + frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
| // Code slot popped. |
| - __ push(r0); |
| + frame_->Push(r0); |
| // --- Finally block --- |
| __ bind(&finally_block); |
| // Push the state on the stack. |
| - __ push(r2); |
| + frame_->Push(r2); |
| // We keep two elements on the stack - the (possibly faked) result |
| // and the state - while evaluating the finally block. Record it, so |
| @@ -1840,8 +1897,8 @@ |
| VisitStatements(node->finally_block()->statements()); |
| // Restore state and return value or faked TOS. |
| - __ pop(r2); |
| - __ pop(r0); |
| + frame_->Pop(r2); |
| + frame_->Pop(r0); |
| break_stack_height_ -= kFinallyStackSize; |
| // Generate code to jump to the right destination for all used (formerly) |
| @@ -1865,7 +1922,7 @@ |
| __ b(ne, &exit); |
| // Rethrow exception. |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kReThrow, 1); |
| // Done. |
| @@ -1886,12 +1943,12 @@ |
| // Push the boilerplate on the stack. |
| __ mov(r0, Operand(boilerplate)); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Create a new closure. |
| - __ push(cp); |
| + frame_->Push(cp); |
| __ CallRuntime(Runtime::kNewClosure, 2); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| @@ -1932,16 +1989,16 @@ |
| ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| // For now, just do a runtime call. |
| - __ push(cp); |
| + frame_->Push(cp); |
| __ mov(r0, Operand(slot->var()->name())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| if (typeof_state == INSIDE_TYPEOF) { |
| __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| } else { |
| __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| } |
| - __ push(r0); |
| + frame_->Push(r0); |
| } else { |
| // Note: We would like to keep the assert below, but it fires because of |
| @@ -1950,16 +2007,16 @@ |
| // Special handling for locals allocated in registers. |
| __ ldr(r0, SlotOperand(slot, r2)); |
| - __ push(r0); |
| + frame_->Push(r0); |
| 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"); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| __ cmp(r0, Operand(Factory::the_hole_value())); |
| __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| } |
| } |
| @@ -1989,7 +2046,7 @@ |
| void CodeGenerator::VisitLiteral(Literal* node) { |
| Comment cmnt(masm_, "[ Literal"); |
| __ mov(r0, Operand(node->handle())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| @@ -2015,19 +2072,19 @@ |
| // If the entry is undefined we call the runtime system to computed |
| // the literal. |
| - __ push(r1); // literal array (0) |
| + frame_->Push(r1); // literal array (0) |
| __ mov(r0, Operand(Smi::FromInt(node->literal_index()))); |
| - __ push(r0); // literal index (1) |
| + frame_->Push(r0); // literal index (1) |
| __ mov(r0, Operand(node->pattern())); // RegExp pattern (2) |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(node->flags())); // RegExp flags (3) |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
| __ mov(r2, Operand(r0)); |
| __ bind(&done); |
| // Push the literal. |
| - __ push(r2); |
| + frame_->Push(r2); |
| } |
| @@ -2089,11 +2146,11 @@ |
| __ bind(deferred->exit()); |
| // Push the object literal boilerplate. |
| - __ push(r2); |
| + frame_->Push(r2); |
| // Clone the boilerplate object. |
| __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); |
| - __ push(r0); // save the result |
| + frame_->Push(r0); // save the result |
| // r0: cloned object literal |
| for (int i = 0; i < node->properties()->length(); i++) { |
| @@ -2104,7 +2161,7 @@ |
| case ObjectLiteral::Property::CONSTANT: break; |
| case ObjectLiteral::Property::COMPUTED: // fall through |
| case ObjectLiteral::Property::PROTOTYPE: { |
| - __ push(r0); // dup the result |
| + frame_->Push(r0); // dup the result |
| Load(key); |
| Load(value); |
| __ CallRuntime(Runtime::kSetProperty, 3); |
| @@ -2113,20 +2170,20 @@ |
| break; |
| } |
| case ObjectLiteral::Property::SETTER: { |
| - __ push(r0); |
| + frame_->Push(r0); |
| Load(key); |
| __ mov(r0, Operand(Smi::FromInt(1))); |
| - __ push(r0); |
| + frame_->Push(r0); |
| Load(value); |
| __ CallRuntime(Runtime::kDefineAccessor, 4); |
| __ ldr(r0, frame_->Top()); |
| break; |
| } |
| case ObjectLiteral::Property::GETTER: { |
| - __ push(r0); |
| + frame_->Push(r0); |
| Load(key); |
| __ mov(r0, Operand(Smi::FromInt(0))); |
| - __ push(r0); |
| + frame_->Push(r0); |
| Load(value); |
| __ CallRuntime(Runtime::kDefineAccessor, 4); |
| __ ldr(r0, frame_->Top()); |
| @@ -2142,15 +2199,15 @@ |
| // Call runtime to create the array literal. |
| __ mov(r0, Operand(node->literals())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Load the function of this frame. |
| __ ldr(r0, frame_->Function()); |
| __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
| // Push the resulting array literal on the stack. |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Generate code to set the elements in the array that are not |
| // literals. |
| @@ -2162,7 +2219,7 @@ |
| if (value->AsLiteral() == NULL) { |
| // The property must be set by generated code. |
| Load(value); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| // Fetch the object literal |
| __ ldr(r1, frame_->Top()); |
| @@ -2198,12 +2255,12 @@ |
| Literal* literal = node->value()->AsLiteral(); |
| if (literal != NULL && literal->handle()->IsSmi()) { |
| SmiOperation(node->binary_op(), literal->handle(), false); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } else { |
| Load(node->value()); |
| GenericBinaryOperation(node->binary_op()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| } |
| @@ -2233,7 +2290,7 @@ |
| Load(node->exception()); |
| __ RecordPosition(node->position()); |
| __ CallRuntime(Runtime::kThrow, 1); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| @@ -2274,7 +2331,7 @@ |
| // Push the name of the function and the receiver onto the stack. |
| __ mov(r0, Operand(var->name())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Pass the global object as the receiver and let the IC stub |
| // patch the stack to use the global proxy as 'this' in the |
| @@ -2290,8 +2347,8 @@ |
| __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT); |
| __ ldr(cp, frame_->Context()); |
| // Remove the function from the stack. |
| - __ pop(); |
| - __ push(r0); |
| + frame_->Pop(); |
| + frame_->Push(r0); |
| } else if (var != NULL && var->slot() != NULL && |
| var->slot()->type() == Slot::LOOKUP) { |
| @@ -2300,19 +2357,19 @@ |
| // ---------------------------------- |
| // Load the function |
| - __ push(cp); |
| + frame_->Push(cp); |
| __ mov(r0, Operand(var->name())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| // r0: slot value; r1: receiver |
| // Load the receiver. |
| - __ push(r0); // function |
| - __ push(r1); // receiver |
| + frame_->Push(r0); // function |
| + frame_->Push(r1); // receiver |
| // Call the function. |
| CallWithArguments(args, node->position()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } else if (property != NULL) { |
| // Check if the key is a literal string. |
| @@ -2325,7 +2382,7 @@ |
| // Push the name of the function and the receiver onto the stack. |
| __ mov(r0, Operand(literal->handle())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| Load(property->obj()); |
| // Load the arguments. |
| @@ -2338,9 +2395,9 @@ |
| __ ldr(cp, frame_->Context()); |
| // Remove the function from the stack. |
| - __ pop(); |
| + frame_->Pop(); |
| - __ push(r0); // push after get rid of function from the stack |
| + frame_->Push(r0); // push after get rid of function from the stack |
| } else { |
| // ------------------------------------------- |
| @@ -2353,10 +2410,10 @@ |
| // Pass receiver to called function. |
| __ ldr(r0, frame_->Element(ref.size())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Call the function. |
| CallWithArguments(args, node->position()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| } else { |
| @@ -2372,7 +2429,7 @@ |
| // Call the function. |
| CallWithArguments(args, node->position()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| } |
| @@ -2417,7 +2474,7 @@ |
| ASSERT(args->length() == 1); |
| Label leave; |
| Load(args->at(0)); |
| - __ pop(r0); // r0 contains object. |
| + frame_->Pop(r0); // r0 contains object. |
| // if (object->IsSmi()) return the object. |
| __ tst(r0, Operand(kSmiTagMask)); |
| __ b(eq, &leave); |
| @@ -2430,7 +2487,7 @@ |
| // Load the value. |
| __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); |
| __ bind(&leave); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| @@ -2439,8 +2496,8 @@ |
| Label leave; |
| Load(args->at(0)); // Load the object. |
| Load(args->at(1)); // Load the value. |
| - __ pop(r0); // r0 contains value |
| - __ pop(r1); // r1 contains object |
| + frame_->Pop(r0); // r0 contains value |
| + frame_->Pop(r1); // r1 contains object |
| // if (object->IsSmi()) return object. |
| __ tst(r1, Operand(kSmiTagMask)); |
| __ b(eq, &leave); |
| @@ -2457,14 +2514,14 @@ |
| __ RecordWrite(r1, r2, r3); |
| // Leave. |
| __ bind(&leave); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
| ASSERT(args->length() == 1); |
| Load(args->at(0)); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| __ tst(r0, Operand(kSmiTagMask)); |
| cc_reg_ = eq; |
| } |
| @@ -2473,7 +2530,7 @@ |
| void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| ASSERT(args->length() == 1); |
| Load(args->at(0)); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| __ tst(r0, Operand(kSmiTagMask | 0x80000000)); |
| cc_reg_ = eq; |
| } |
| @@ -2485,7 +2542,7 @@ |
| void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| ASSERT(args->length() == 2); |
| __ mov(r0, Operand(Factory::undefined_value())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| @@ -2496,7 +2553,7 @@ |
| // We need the CC bits to come out as not_equal in the case where the |
| // object is a smi. This can't be done with the usual test opcode so |
| // we use XOR to get the right CC bits. |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| __ and_(r1, r0, Operand(kSmiTagMask)); |
| __ eor(r1, r1, Operand(kSmiTagMask), SetCC); |
| __ b(ne, &answer); |
| @@ -2520,7 +2577,7 @@ |
| // Call the shared stub to get to the arguments.length. |
| ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
| __ CallStub(&stub); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| @@ -2530,13 +2587,13 @@ |
| // Satisfy contract with ArgumentsAccessStub: |
| // Load the key into r1 and the formal parameters count into r0. |
| Load(args->at(0)); |
| - __ pop(r1); |
| + frame_->Pop(r1); |
| __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
| // Call the shared stub to get to arguments[key]. |
| ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| __ CallStub(&stub); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| @@ -2546,8 +2603,8 @@ |
| // Load the two objects into registers and perform the comparison. |
| Load(args->at(0)); |
| Load(args->at(1)); |
| - __ pop(r0); |
| - __ pop(r1); |
| + frame_->Pop(r0); |
| + frame_->Pop(r1); |
| __ cmp(r0, Operand(r1)); |
| cc_reg_ = eq; |
| } |
| @@ -2566,16 +2623,16 @@ |
| // Call the C runtime function. |
| __ CallRuntime(function, args->length()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } else { |
| // Prepare stack for calling JS runtime function. |
| __ mov(r0, Operand(node->name())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Push the builtins object found in the current global object. |
| __ ldr(r1, GlobalObject()); |
| __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset)); |
| - __ push(r0); |
| + frame_->Push(r0); |
| for (int i = 0; i < args->length(); i++) Load(args->at(i)); |
| @@ -2583,8 +2640,8 @@ |
| Handle<Code> stub = ComputeCallInitialize(args->length()); |
| __ Call(stub, RelocInfo::CODE_TARGET); |
| __ ldr(cp, frame_->Context()); |
| - __ pop(); |
| - __ push(r0); |
| + frame_->Pop(); |
| + frame_->Push(r0); |
| } |
| } |
| @@ -2616,20 +2673,20 @@ |
| if (variable->is_global()) { |
| LoadGlobal(); |
| __ mov(r0, Operand(variable->name())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(1)); // not counting receiver |
| __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
| } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| // lookup the context holding the named variable |
| - __ push(cp); |
| + frame_->Push(cp); |
| __ mov(r0, Operand(variable->name())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ CallRuntime(Runtime::kLookupContext, 2); |
| // r0: context |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(variable->name())); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(1)); // not counting receiver |
| __ InvokeBuiltin(Builtins::DELETE, CALL_JS); |
| @@ -2642,21 +2699,21 @@ |
| } else { |
| // Default: Result of deleting expressions is true. |
| Load(node->expression()); // may have side-effects |
| - __ pop(); |
| + frame_->Pop(); |
| __ mov(r0, Operand(Factory::true_value())); |
| } |
| - __ push(r0); |
| + frame_->Push(r0); |
| } else if (op == Token::TYPEOF) { |
| // Special case for loading the typeof expression; see comment on |
| // LoadTypeofExpression(). |
| LoadTypeofExpression(node->expression()); |
| __ CallRuntime(Runtime::kTypeof, 1); |
| - __ push(r0); // r0 has result |
| + frame_->Push(r0); // r0 has result |
| } else { |
| Load(node->expression()); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| switch (op) { |
| case Token::NOT: |
| case Token::DELETE: |
| @@ -2677,7 +2734,7 @@ |
| __ tst(r0, Operand(kSmiTagMask)); |
| __ b(eq, &smi_label); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(0)); // not counting receiver |
| __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS); |
| @@ -2700,7 +2757,7 @@ |
| Label continue_label; |
| __ tst(r0, Operand(kSmiTagMask)); |
| __ b(eq, &continue_label); |
| - __ push(r0); |
| + frame_->Push(r0); |
| __ mov(r0, Operand(0)); // not counting receiver |
| __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS); |
| __ bind(&continue_label); |
| @@ -2709,7 +2766,7 @@ |
| default: |
| UNREACHABLE(); |
| } |
| - __ push(r0); // r0 has result |
| + frame_->Push(r0); // r0 has result |
| } |
| } |
| @@ -2726,13 +2783,13 @@ |
| // Postfix: Make room for the result. |
| if (is_postfix) { |
| __ mov(r0, Operand(0)); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| { Reference target(this, node->expression()); |
| if (target.is_illegal()) return; |
| target.GetValue(NOT_INSIDE_TYPEOF); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| Label slow, exit; |
| @@ -2787,12 +2844,12 @@ |
| // Store the new value in the target if not const. |
| __ bind(&exit); |
| - __ push(r0); |
| + frame_->Push(r0); |
| if (!is_const) target.SetValue(NOT_CONST_INIT); |
| } |
| // Postfix: Discard the new value and use the old. |
| - if (is_postfix) __ pop(r0); |
| + if (is_postfix) frame_->Pop(r0); |
| } |
| @@ -2834,7 +2891,7 @@ |
| Label pop_and_continue, exit; |
| __ ldr(r0, frame_->Top()); // dup the stack top |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Avoid popping the result if it converts to 'false' using the |
| // standard ToBoolean() conversion as described in ECMA-262, |
| // section 9.2, page 30. |
| @@ -2843,7 +2900,7 @@ |
| // Pop the result of evaluating the first part. |
| __ bind(&pop_and_continue); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| // Evaluate right side expression. |
| __ bind(&is_true); |
| @@ -2875,7 +2932,7 @@ |
| Label pop_and_continue, exit; |
| __ ldr(r0, frame_->Top()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| // Avoid popping the result if it converts to 'true' using the |
| // standard ToBoolean() conversion as described in ECMA-262, |
| // section 9.2, page 30. |
| @@ -2884,7 +2941,7 @@ |
| // Pop the result of evaluating the first part. |
| __ bind(&pop_and_continue); |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| // Evaluate right side expression. |
| __ bind(&is_false); |
| @@ -2913,14 +2970,14 @@ |
| Load(node->right()); |
| GenericBinaryOperation(node->op()); |
| } |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| } |
| void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
| __ ldr(r0, frame_->Function()); |
| - __ push(r0); |
| + frame_->Push(r0); |
| } |
| @@ -2946,7 +3003,7 @@ |
| if (left_is_null || right_is_null) { |
| Load(left_is_null ? right : left); |
| Label exit, undetectable; |
| - __ pop(r0); |
| + frame_->Pop(r0); |
| __ cmp(r0, Operand(Factory::null_value())); |
| // The 'null' value is only equal to 'undefined' if using |
| @@ -2990,7 +3047,7 @@ |
| // Load the operand, move it to register r1. |
| LoadTypeofExpression(operation->expression()); |
| - __ pop(r1); |
| + frame_->Pop(r1); |
| if (check->Equals(Heap::number_symbol())) { |
| __ tst(r1, Operand(kSmiTagMask)); |
| @@ -3102,7 +3159,7 @@ |
| case Token::IN: |
| __ mov(r0, Operand(1)); // not counting receiver |
| __ InvokeBuiltin(Builtins::IN, CALL_JS); |
| - __ push(r0); |
| + frame_->Push(r0); |
| break; |
| case Token::INSTANCEOF: |
| @@ -3127,34 +3184,6 @@ |
| } |
| -void CodeGenerator::EnterJSFrame() { |
| -#if defined(DEBUG) |
| - { Label done, fail; |
| - __ tst(r1, Operand(kSmiTagMask)); |
| - __ b(eq, &fail); |
| - __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| - __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| - __ cmp(r2, Operand(JS_FUNCTION_TYPE)); |
| - __ b(eq, &done); |
| - __ bind(&fail); |
| - __ stop("CodeGenerator::EnterJSFrame - r1 not a function"); |
| - __ bind(&done); |
| - } |
| -#endif // DEBUG |
| - |
| - __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
| - __ add(fp, sp, Operand(2 * kPointerSize)); // Adjust FP to point to saved FP. |
| -} |
| - |
| - |
| -void CodeGenerator::ExitJSFrame() { |
| - // Drop the execution stack down to the frame pointer and restore the caller |
| - // frame pointer and return address. |
| - __ mov(sp, fp); |
| - __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
| -} |
| - |
| - |
| #undef __ |
| #define __ masm-> |
| @@ -3179,6 +3208,7 @@ |
| ASSERT(!is_illegal()); |
| ASSERT(!cgen_->has_cc()); |
| MacroAssembler* masm = cgen_->masm(); |
| + VirtualFrame* frame = cgen_->frame(); |
| Property* property = expression_->AsProperty(); |
| if (property != NULL) { |
| __ RecordPosition(property->position()); |
| @@ -3212,7 +3242,7 @@ |
| } else { |
| __ Call(ic, RelocInfo::CODE_TARGET); |
| } |
| - __ push(r0); |
| + frame->Push(r0); |
| break; |
| } |
| @@ -3224,7 +3254,7 @@ |
| // TODO(1224671): Implement inline caching for keyed loads as on ia32. |
| GetPropertyStub stub; |
| __ CallStub(&stub); |
| - __ push(r0); |
| + frame->Push(r0); |
| break; |
| } |
| @@ -3238,6 +3268,7 @@ |
| ASSERT(!is_illegal()); |
| ASSERT(!cgen_->has_cc()); |
| MacroAssembler* masm = cgen_->masm(); |
| + VirtualFrame* frame = cgen_->frame(); |
| Property* property = expression_->AsProperty(); |
| if (property != NULL) { |
| __ RecordPosition(property->position()); |
| @@ -3252,9 +3283,9 @@ |
| ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
| // For now, just do a runtime call. |
| - __ push(cp); |
| + frame->Push(cp); |
| __ mov(r0, Operand(slot->var()->name())); |
| - __ push(r0); |
| + frame->Push(r0); |
| if (init_state == CONST_INIT) { |
| // Same as the case for a normal store, but ignores attribute |
| @@ -3278,7 +3309,7 @@ |
| } |
| // Storing a variable must keep the (new) value on the expression |
| // stack. This is necessary for compiling assignment expressions. |
| - __ push(r0); |
| + frame->Push(r0); |
| } else { |
| ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
| @@ -3304,9 +3335,9 @@ |
| // 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. |
| - __ pop(r0); |
| + frame->Pop(r0); |
| __ str(r0, cgen_->SlotOperand(slot, r2)); |
| - __ push(r0); |
| + frame->Push(r0); |
| if (slot->type() == Slot::CONTEXT) { |
| // Skip write barrier if the written value is a smi. |
| __ tst(r0, Operand(kSmiTagMask)); |
| @@ -3329,13 +3360,13 @@ |
| case NAMED: { |
| Comment cmnt(masm, "[ Store to named Property"); |
| // Call the appropriate IC code. |
| - __ pop(r0); // value |
| + frame->Pop(r0); // value |
| // Setup the name register. |
| Handle<String> name(GetName()); |
| __ mov(r2, Operand(name)); |
| Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
| __ Call(ic, RelocInfo::CODE_TARGET); |
| - __ push(r0); |
| + frame->Push(r0); |
| break; |
| } |
| @@ -3344,10 +3375,10 @@ |
| Property* property = expression_->AsProperty(); |
| ASSERT(property != NULL); |
| __ RecordPosition(property->position()); |
| - __ pop(r0); // value |
| + frame->Pop(r0); // value |
| SetPropertyStub stub; |
| __ CallStub(&stub); |
| - __ push(r0); |
| + frame->Push(r0); |
| break; |
| } |