Emit pushes and pops through the virtual frame on ARM. Merging of

frames is not yet handled.  The ARM code generator should be back in
line with the IA32 one.
Review URL: http://codereview.chromium.org/9182

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@706 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a6554f87
......@@ -49,6 +49,70 @@ VirtualFrame::VirtualFrame(CodeGenerator* cgen) {
}
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() { Drop(1); }
void VirtualFrame::Pop(Register reg) {
__ pop(reg);
}
void VirtualFrame::Push(Register reg) {
__ push(reg);
}
// -------------------------------------------------------------------------
// CodeGenState implementation.
......@@ -99,7 +163,6 @@ CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
// Calling conventions:
// r0: the number of arguments
// fp: frame pointer
// sp: stack pointer
......@@ -127,9 +190,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
// pp: caller's parameter pointer
// cp: callee's context
{ Comment cmnt(masm_, "[ enter JS frame");
EnterJSFrame();
}
frame_->Enter();
// tos: code slot
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
......@@ -139,20 +200,13 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
#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 +220,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
__ 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 +252,9 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
}
}
// 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 +269,31 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
__ 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 +308,7 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
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 +327,13 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
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 +397,17 @@ MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
}
// 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 +415,13 @@ void CodeGenerator::LoadCondition(Expression* x,
}
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 +438,11 @@ void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
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 +458,7 @@ void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
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 +468,7 @@ void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
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 +479,15 @@ void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
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 +525,6 @@ Reference::~Reference() {
void CodeGenerator::LoadReference(Reference* ref) {
Comment cmnt(masm_, "[ LoadReference");
Expression* e = ref->expression();
Property* property = e->AsProperty();
Variable* var = e->AsVariableProxy()->AsVariable();
......@@ -507,15 +566,15 @@ void CodeGenerator::LoadReference(Reference* ref) {
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) {
// 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 +583,10 @@ void CodeGenerator::UnloadReference(Reference* ref) {
// 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 +609,9 @@ void CodeGenerator::ToBoolean(Label* true_target,
__ 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 +712,8 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op) {
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 +732,9 @@ void CodeGenerator::GenericBinaryOperation(Token::Value op) {
}
case Token::COMMA:
__ pop(r0);
frame_->Pop(r0);
// simply discard left value
__ pop();
frame_->Pop();
break;
default:
......@@ -764,8 +822,8 @@ class DeferredInlinedSmiOperation: public DeferredCode {
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 +836,7 @@ void CodeGenerator::SmiOperation(Token::Value op,
int int_value = Smi::cast(*value)->value();
Label exit;
__ pop(r0);
frame_->Pop(r0);
switch (op) {
case Token::ADD: {
......@@ -831,8 +889,8 @@ void CodeGenerator::SmiOperation(Token::Value op,
case Token::SAR: {
if (reversed) {
__ mov(ip, Operand(value));
__ push(ip);
__ push(r0);
frame_->Push(ip);
frame_->Push(r0);
GenericBinaryOperation(op);
} else {
......@@ -882,13 +940,13 @@ void CodeGenerator::SmiOperation(Token::Value op,
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 +968,18 @@ void CodeGenerator::Comparison(Condition cc, bool strict) {
// 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 +996,14 @@ void CodeGenerator::Comparison(Condition cc, bool strict) {
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 +1053,7 @@ void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
// Restore context and pop function from the stack.
__ ldr(cp, frame_->Context());
__ pop(); // discard the TOS
frame_->Pop(); // discard the TOS
}
......@@ -1027,10 +1085,10 @@ void CodeGenerator::VisitBlock(Block* node) {
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 +1108,26 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
// 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 +1154,7 @@ void CodeGenerator::VisitDeclaration(Declaration* node) {
// 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 +1165,7 @@ void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
Expression* expression = node->expression();
expression->MarkAsStatement();
Load(expression);
__ pop();
frame_->Pop();
}
......@@ -1172,7 +1230,7 @@ void CodeGenerator::VisitIfStatement(IfStatement* node) {
if (has_cc()) {
cc_reg_ = al;
} else {
__ pop(r0); // __ Pop(no_reg)
frame_->Pop();
}
}
......@@ -1182,10 +1240,8 @@ void CodeGenerator::VisitIfStatement(IfStatement* node) {
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 +1266,7 @@ void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
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 +1317,7 @@ void CodeGenerator::GenerateFastCaseSwitchJumpTable(
ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
__ pop(r0);
frame_->Pop(r0);
// Test for a Smi value in a HeapNumber.
Label is_smi;
......@@ -1271,7 +1327,7 @@ void CodeGenerator::GenerateFastCaseSwitchJumpTable(
__ 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 +1396,7 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
__ 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 +1404,7 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
// 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 +1423,7 @@ void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
__ b(&default_case);
} else {
// Remove the switch value from the stack.
__ pop(r0);
frame_->Pop();
}
__ bind(&fall_through);
......@@ -1463,7 +1519,7 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
// 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 +1544,7 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ b(hs, &jsobject);
__ bind(&primitive);
__ push(r0);
frame_->Push(r0);
__ mov(r0, Operand(0));
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
......@@ -1496,8 +1552,8 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ 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 +1570,28 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
__ 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 +1602,9 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
// 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 +1637,8 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
// 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 +1652,12 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
// 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 +1669,20 @@ void CodeGenerator::VisitForInStatement(ForInStatement* node) {
// 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 +1697,10 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
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 +1710,7 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
}
// Remove the exception from the stack.
__ pop();
frame_->Pop();
VisitStatements(node->catch_block()->statements());
__ b(&exit);
......@@ -1682,7 +1737,7 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
// 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 +1757,7 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
__ 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 +1776,7 @@ void CodeGenerator::VisitTryCatch(TryCatch* node) {
__ 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 +1799,7 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
__ 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 +1837,7 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
// 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 +1849,11 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
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 +1863,7 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
// 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 +1874,15 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
__ 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 +1895,8 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
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 +1920,7 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
__ b(ne, &exit);
// Rethrow exception.
__ push(r0);
frame_->Push(r0);
__ CallRuntime(Runtime::kReThrow, 1);
// Done.
......@@ -1886,12 +1941,12 @@ void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
// 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 +1987,16 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
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 +2005,16 @@ void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
// 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 +2044,7 @@ void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
void CodeGenerator::VisitLiteral(Literal* node) {
Comment cmnt(masm_, "[ Literal");
__ mov(r0, Operand(node->handle()));
__ push(r0);
frame_->Push(r0);
}
......@@ -2015,19 +2070,19 @@ void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
// 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 +2144,11 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
__ 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 +2159,7 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
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 +2168,20 @@ void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
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 +2197,15 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
// 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 +2217,7 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
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 +2253,12 @@ void CodeGenerator::VisitAssignment(Assignment* node) {
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 +2288,7 @@ void CodeGenerator::VisitThrow(Throw* node) {
Load(node->exception());
__ RecordPosition(node->position());
__ CallRuntime(Runtime::kThrow, 1);
__ push(r0);
frame_->Push(r0);
}
......@@ -2274,7 +2329,7 @@ void CodeGenerator::VisitCall(Call* node) {
// 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 +2345,8 @@ void CodeGenerator::VisitCall(Call* node) {
__ 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 +2355,19 @@ void CodeGenerator::VisitCall(Call* node) {
// ----------------------------------
// 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 +2380,7 @@ void CodeGenerator::VisitCall(Call* node) {
// 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 +2393,9 @@ void CodeGenerator::VisitCall(Call* node) {
__ 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 +2408,10 @@ void CodeGenerator::VisitCall(Call* node) {
// 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 +2427,7 @@ void CodeGenerator::VisitCall(Call* node) {
// Call the function.
CallWithArguments(args, node->position());
__ push(r0);
frame_->Push(r0);
}
}
......@@ -2417,7 +2472,7 @@ void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
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 +2485,7 @@ void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
// Load the value.
__ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
__ bind(&leave);
__ push(r0);
frame_->Push(r0);
}
......@@ -2439,8 +2494,8 @@ void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
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 +2512,14 @@ void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
__ 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 +2528,7 @@ void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
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 +2540,7 @@ void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
ASSERT(args->length() == 2);
__ mov(r0, Operand(Factory::undefined_value()));
__ push(r0);
frame_->Push(r0);
}
......@@ -2496,7 +2551,7 @@ void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
// 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 +2575,7 @@ void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
// Call the shared stub to get to the arguments.length.
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
__ CallStub(&stub);
__ push(r0);
frame_->Push(r0);
}
......@@ -2530,13 +2585,13 @@ void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
// 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 +2601,8 @@ void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
// 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 +2621,16 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
// 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 +2638,8 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
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 +2671,20 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
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 +2697,21 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
} 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 +2732,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
__ 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 +2755,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
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 +2764,7 @@ void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
default:
UNREACHABLE();
}
__ push(r0); // r0 has result
frame_->Push(r0); // r0 has result
}
}
......@@ -2726,13 +2781,13 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
// 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 +2842,12 @@ void CodeGenerator::VisitCountOperation(CountOperation* node) {
// 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 +2889,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
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 +2898,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
// 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 +2930,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
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 +2939,7 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
// 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 +2968,14 @@ void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
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 +3001,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
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 +3045,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
// 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 +3157,7 @@ void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
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 +3182,6 @@ void CodeGenerator::RecordStatementPosition(Node* node) {
}
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 +3206,7 @@ void Reference::GetValue(TypeofState typeof_state) {
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 +3240,7 @@ void Reference::GetValue(TypeofState typeof_state) {
} else {
__ Call(ic, RelocInfo::CODE_TARGET);
}
__ push(r0);
frame->Push(r0);
break;
}
......@@ -3224,7 +3252,7 @@ void Reference::GetValue(TypeofState typeof_state) {
// TODO(1224671): Implement inline caching for keyed loads as on ia32.
GetPropertyStub stub;
__ CallStub(&stub);
__ push(r0);
frame->Push(r0);
break;
}
......@@ -3238,6 +3266,7 @@ void Reference::SetValue(InitState init_state) {
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 +3281,9 @@ void Reference::SetValue(InitState init_state) {
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 +3307,7 @@ void Reference::SetValue(InitState init_state) {
}
// 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 +3333,9 @@ void Reference::SetValue(InitState init_state) {
// 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 +3358,13 @@ void Reference::SetValue(InitState init_state) {
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 +3373,10 @@ void Reference::SetValue(InitState init_state) {
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;
}
......
......@@ -49,6 +49,11 @@ class VirtualFrame BASE_EMBEDDED {
public:
explicit VirtualFrame(CodeGenerator* cgen);
void Enter();
void Exit();
void AllocateLocals();
MemOperand Top() const { return MemOperand(sp, 0); }
MemOperand Element(int index) const {
......@@ -70,6 +75,13 @@ class VirtualFrame BASE_EMBEDDED {
return MemOperand(fp, (1 + parameter_count_ - index) * kPointerSize);
}
inline void Drop(int count);
inline void Pop();
inline void Pop(Register reg);
inline void Push(Register reg);
private:
static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
......@@ -195,6 +207,8 @@ class CodeGenerator: public Visitor {
// Accessors
MacroAssembler* masm() { return masm_; }
VirtualFrame* frame() const { return frame_; }
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
......@@ -366,11 +380,6 @@ class CodeGenerator: public Visitor {
// should be generated or not.
void RecordStatementPosition(Node* node);
// Activation frames.
void EnterJSFrame();
void ExitJSFrame();
bool is_eval_; // Tells whether code is generated for eval.
Handle<Script> script_;
List<DeferredCode*> deferred_;
......
......@@ -99,9 +99,7 @@ void VirtualFrame::Drop(int count) {
}
void VirtualFrame::Pop() {
__ add(Operand(esp), Immediate(kPointerSize));
}
void VirtualFrame::Pop() { Drop(1); }
void VirtualFrame::Pop(Register reg) {
......@@ -267,10 +265,8 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
__ int3();
__ bind(&verified_true);
}
// Update context local.
__ mov(frame_->Context(), esi);
// Restore the arguments array pointer, if any.
}
// TODO(1241774): Improve this code:
......@@ -310,10 +306,10 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
// This section stores the pointer to the arguments object that
// was allocated and copied into above. If the address was not
// saved to TOS, we push ecx onto the stack.
// Store the arguments object.
// This must happen after context initialization because
// the arguments object 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 (arguments_object_allocated) {
ASSERT(scope_->arguments() != NULL);
ASSERT(scope_->arguments_shadow() != NULL);
......@@ -341,18 +337,17 @@ void CodeGenerator::GenCode(FunctionLiteral* fun) {
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(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;
}
......@@ -448,10 +443,11 @@ Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
// 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'.
// (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,
......@@ -463,6 +459,14 @@ void CodeGenerator::LoadCondition(Expression* x,
Visit(x);
}
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);
......@@ -476,7 +480,6 @@ void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
if (has_cc()) {
// convert cc_reg_ into a bool
Label loaded, materialize_true;
__ j(cc_reg_, &materialize_true);
frame_->Push(Immediate(Factory::false_value()));
......@@ -663,7 +666,7 @@ void CodeGenerator::ToBoolean(Label* true_target, Label* false_target) {
frame_->Push(eax); // Undo the pop(eax) from above.
ToBooleanStub stub;
__ CallStub(&stub);
// Convert result (eax) to condition code.
// Convert the result (eax) to condition code.
__ test(eax, Operand(eax));
ASSERT(not_equal == not_zero);
......@@ -2198,7 +2201,6 @@ void CodeGenerator::VisitTryFinally(TryFinally* node) {
frame_->Pop(Operand::StaticVariable(handler_address));
frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// Next_sp popped.
// Preserve the TOS in a register across stack manipulation.
frame_->Push(eax);
// --- Finally block ---
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment