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; |
} |