Index: src/codegen-arm.cc |
=================================================================== |
--- src/codegen-arm.cc (revision 682) |
+++ src/codegen-arm.cc (working copy) |
@@ -35,7 +35,21 @@ |
namespace v8 { namespace internal { |
+#define __ masm_-> |
+ |
// ------------------------------------------------------------------------- |
+// VirtualFrame implementation. |
+ |
+VirtualFrame::VirtualFrame(CodeGenerator* cgen) { |
+ ASSERT(cgen->scope() != NULL); |
+ |
+ masm_ = cgen->masm(); |
+ frame_local_count_ = cgen->scope()->num_stack_slots(); |
+ parameter_count_ = cgen->scope()->num_parameters(); |
+} |
+ |
+ |
+// ------------------------------------------------------------------------- |
// CodeGenState implementation. |
CodeGenState::CodeGenState(CodeGenerator* owner) |
@@ -67,11 +81,9 @@ |
} |
-// ----------------------------------------------------------------------------- |
+// ------------------------------------------------------------------------- |
// CodeGenerator implementation |
-#define __ masm_-> |
- |
CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, |
bool is_eval) |
: is_eval_(is_eval), |
@@ -79,6 +91,7 @@ |
deferred_(8), |
masm_(new MacroAssembler(NULL, buffer_size)), |
scope_(NULL), |
+ frame_(NULL), |
cc_reg_(al), |
state_(NULL), |
break_stack_height_(0) { |
@@ -94,13 +107,17 @@ |
// cp: callee's context |
void CodeGenerator::GenCode(FunctionLiteral* fun) { |
- Scope* scope = fun->scope(); |
ZoneList<Statement*>* body = fun->body(); |
// Initialize state. |
- { CodeGenState state(this); |
- scope_ = scope; |
- cc_reg_ = al; |
+ ASSERT(scope_ == NULL); |
+ scope_ = fun->scope(); |
+ ASSERT(frame_ == NULL); |
+ VirtualFrame virtual_frame(this); |
+ frame_ = &virtual_frame; |
+ cc_reg_ = al; |
+ { |
+ CodeGenState state(this); |
// Entry |
// stack: function, receiver, arguments, return address |
@@ -122,19 +139,19 @@ |
#endif |
// Allocate space for locals and initialize them. |
- if (scope->num_stack_slots() > 0) { |
+ 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++) { |
+ for (int i = 0; i < scope_->num_stack_slots(); i++) { |
__ push(ip); |
} |
} |
- if (scope->num_heap_slots() > 0) { |
+ if (scope_->num_heap_slots() > 0) { |
// Allocate local context. |
// Get outer context and create a new context based on it. |
- __ ldr(r0, FunctionOperand()); |
+ __ ldr(r0, frame_->Function()); |
__ push(r0); |
__ CallRuntime(Runtime::kNewContext, 1); // r0 holds the result |
@@ -146,7 +163,7 @@ |
__ bind(&verified_true); |
} |
// Update context local. |
- __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
+ __ str(cp, frame_->Context()); |
} |
// TODO(1241774): Improve this code!!! |
@@ -164,12 +181,12 @@ |
// order: such a parameter is copied repeatedly into the same |
// context location and thus the last value is what is seen inside |
// the function. |
- for (int i = 0; i < scope->num_parameters(); i++) { |
- Variable* par = scope->parameter(i); |
+ for (int i = 0; i < scope_->num_parameters(); i++) { |
+ Variable* par = scope_->parameter(i); |
Slot* slot = par->slot(); |
if (slot != NULL && slot->type() == Slot::CONTEXT) { |
- ASSERT(!scope->is_global_scope()); // no parameters in global scope |
- __ ldr(r1, ParameterOperand(i)); |
+ ASSERT(!scope_->is_global_scope()); // no parameters in global scope |
+ __ ldr(r1, frame_->Parameter(i)); |
// Loads r2 with context; used below in RecordWrite. |
__ str(r1, SlotOperand(slot, r2)); |
// Load the offset into r3. |
@@ -184,18 +201,18 @@ |
// Store the arguments object. |
// This must happen after context initialization because |
// the arguments array may be stored in the context! |
- if (scope->arguments() != NULL) { |
- ASSERT(scope->arguments_shadow() != NULL); |
+ if (scope_->arguments() != NULL) { |
+ ASSERT(scope_->arguments_shadow() != NULL); |
Comment cmnt(masm_, "[ allocate arguments object"); |
- { Reference shadow_ref(this, scope->arguments_shadow()); |
- { Reference arguments_ref(this, scope->arguments()); |
+ { Reference shadow_ref(this, scope_->arguments_shadow()); |
+ { Reference arguments_ref(this, scope_->arguments()); |
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
- __ ldr(r2, FunctionOperand()); |
+ __ ldr(r2, frame_->Function()); |
// The receiver is below the arguments, the return address, |
// and the frame pointer on the stack. |
- const int kReceiverDisplacement = 2 + scope->num_parameters(); |
+ const int kReceiverDisplacement = 2 + scope_->num_parameters(); |
__ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize)); |
- __ mov(r0, Operand(Smi::FromInt(scope->num_parameters()))); |
+ __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters()))); |
__ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit()); |
__ CallStub(&stub); |
Kevin Millikin (Chromium)
2008/11/04 08:39:59
This is the only place that "ReceiverOperand" woul
|
__ push(r0); |
@@ -210,13 +227,13 @@ |
// functions (source elements). In case of an illegal |
// redeclaration we need to handle that instead of processing the |
// declarations. |
- if (scope->HasIllegalRedeclaration()) { |
+ if (scope_->HasIllegalRedeclaration()) { |
Comment cmnt(masm_, "[ illegal redeclarations"); |
- scope->VisitIllegalRedeclaration(this); |
+ scope_->VisitIllegalRedeclaration(this); |
} else { |
Comment cmnt(masm_, "[ declarations"); |
// ProcessDeclarations calls DeclareGlobals indirectly |
- ProcessDeclarations(scope->declarations()); |
+ ProcessDeclarations(scope_->declarations()); |
// Bail out if a stack-overflow exception occurred when |
// processing declarations. |
@@ -233,7 +250,7 @@ |
// Compile the body of the function in a vanilla state. Don't |
// bother compiling all the code if the scope has an illegal |
// redeclaration. |
- if (!scope->HasIllegalRedeclaration()) { |
+ if (!scope_->HasIllegalRedeclaration()) { |
Comment cmnt(masm_, "[ function body"); |
#ifdef DEBUG |
bool is_builtin = Bootstrapper::IsActive(); |
@@ -272,6 +289,7 @@ |
// Code generation state must be reset. |
scope_ = NULL; |
+ frame_ = NULL; |
ASSERT(!has_cc()); |
ASSERT(state_ == NULL); |
} |
@@ -290,13 +308,10 @@ |
int index = slot->index(); |
switch (slot->type()) { |
case Slot::PARAMETER: |
- return ParameterOperand(index); |
+ return frame_->Parameter(index); |
- case Slot::LOCAL: { |
- ASSERT(0 <= index && index < scope()->num_stack_slots()); |
- const int kLocalOffset = JavaScriptFrameConstants::kLocal0Offset; |
- return MemOperand(fp, kLocalOffset - index * kPointerSize); |
- } |
+ case Slot::LOCAL: |
+ return frame_->Local(index); |
case Slot::CONTEXT: { |
// Follow the context chain if necessary. |
@@ -979,7 +994,7 @@ |
__ CallStub(&call_function); |
// Restore context and pop function from the stack. |
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
+ __ ldr(cp, frame_->Context()); |
__ pop(); // discard the TOS |
} |
@@ -1214,7 +1229,7 @@ |
__ bind(&verified_true); |
} |
// Update context local. |
- __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
+ __ str(cp, frame_->Context()); |
} |
@@ -1223,7 +1238,7 @@ |
// Pop context. |
__ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); |
// Update context local. |
- __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
+ __ str(cp, frame_->Context()); |
} |
@@ -1324,7 +1339,7 @@ |
} else { |
__ bind(&next); |
next.Unuse(); |
- __ ldr(r0, MemOperand(sp, 0)); |
+ __ ldr(r0, frame_->Top()); |
__ push(r0); // duplicate TOS |
Load(clause->label()); |
Comparison(eq, true); |
@@ -1543,29 +1558,29 @@ |
// sp[2] : array or enum cache |
// sp[3] : 0 or map |
// sp[4] : enumerable |
- __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); // load the current count |
- __ ldr(r1, MemOperand(sp, 1 * kPointerSize)); // load the length |
+ __ ldr(r0, frame_->Element(0)); // load the current count |
+ __ ldr(r1, frame_->Element(1)); // load the length |
__ cmp(r0, Operand(r1)); // compare to the array length |
__ b(hs, &cleanup); |
- __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); |
+ __ ldr(r0, frame_->Element(0)); |
// Get the i'th entry of the array. |
- __ ldr(r2, MemOperand(sp, 2 * kPointerSize)); |
+ __ ldr(r2, frame_->Element(2)); |
__ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
__ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
// Get Map or 0. |
- __ ldr(r2, MemOperand(sp, 3 * kPointerSize)); |
+ __ ldr(r2, frame_->Element(3)); |
// Check if this (still) matches the map of the enumerable. |
// If not, we have to filter the key. |
- __ ldr(r1, MemOperand(sp, 4 * kPointerSize)); |
+ __ ldr(r1, frame_->Element(4)); |
__ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); |
__ cmp(r1, Operand(r2)); |
__ b(eq, &end_del_check); |
// Convert the entry to a string (or null if it isn't a property anymore). |
- __ ldr(r0, MemOperand(sp, 4 * kPointerSize)); // push enumerable |
+ __ ldr(r0, frame_->Element(4)); // push enumerable |
__ push(r0); |
__ push(r3); // push entry |
__ mov(r0, Operand(1)); |
@@ -1585,7 +1600,7 @@ |
{ Reference each(this, node->each()); |
if (!each.is_illegal()) { |
if (each.size() > 0) { |
- __ ldr(r0, MemOperand(sp, kPointerSize * each.size())); |
+ __ ldr(r0, frame_->Element(each.size())); |
__ push(r0); |
} |
// If the reference was to a slot we rely on the convenient property |
@@ -1680,9 +1695,10 @@ |
// Unlink from try chain. |
// TOS contains code slot |
- const int kNextOffset = StackHandlerConstants::kNextOffset + |
- StackHandlerConstants::kAddressDisplacement; |
- __ ldr(r1, MemOperand(sp, kNextOffset)); // read next_sp |
+ const int kNextIndex = (StackHandlerConstants::kNextOffset |
+ + StackHandlerConstants::kAddressDisplacement) |
+ / kPointerSize; |
Kevin Millikin (Chromium)
2008/11/04 08:39:59
Changed as per request.
|
+ __ ldr(r1, frame_->Element(kNextIndex)); // read next_sp |
__ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
__ str(r1, MemOperand(r3)); |
ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
@@ -1702,7 +1718,7 @@ |
__ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
__ ldr(sp, MemOperand(r3)); |
- __ ldr(r1, MemOperand(sp, kNextOffset)); |
+ __ ldr(r1, frame_->Element(kNextIndex)); |
__ str(r1, MemOperand(r3)); |
ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
__ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
@@ -1797,9 +1813,10 @@ |
// break from (eg, for...in) may have left stuff on the stack. |
__ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
__ ldr(sp, MemOperand(r3)); |
- const int kNextOffset = StackHandlerConstants::kNextOffset + |
- StackHandlerConstants::kAddressDisplacement; |
- __ ldr(r1, MemOperand(sp, kNextOffset)); |
+ const int kNextIndex = (StackHandlerConstants::kNextOffset |
+ + StackHandlerConstants::kAddressDisplacement) |
+ / kPointerSize; |
+ __ ldr(r1, frame_->Element(kNextIndex)); |
__ str(r1, MemOperand(r3)); |
ASSERT(StackHandlerConstants::kCodeOffset == 0); // first field is code |
__ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize)); |
@@ -1982,7 +1999,7 @@ |
// Retrieve the literal array and check the allocated entry. |
// Load the function of this activation. |
- __ ldr(r1, FunctionOperand()); |
+ __ ldr(r1, frame_->Function()); |
// Load the literals array of the function. |
__ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
@@ -2055,7 +2072,7 @@ |
// Retrieve the literal array and check the allocated entry. |
// Load the function of this activation. |
- __ ldr(r1, FunctionOperand()); |
+ __ ldr(r1, frame_->Function()); |
// Load the literals array of the function. |
__ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
@@ -2092,7 +2109,7 @@ |
Load(value); |
__ CallRuntime(Runtime::kSetProperty, 3); |
// restore r0 |
- __ ldr(r0, MemOperand(sp, 0)); |
+ __ ldr(r0, frame_->Top()); |
break; |
} |
case ObjectLiteral::Property::SETTER: { |
@@ -2102,7 +2119,7 @@ |
__ push(r0); |
Load(value); |
__ CallRuntime(Runtime::kDefineAccessor, 4); |
- __ ldr(r0, MemOperand(sp, 0)); |
+ __ ldr(r0, frame_->Top()); |
break; |
} |
case ObjectLiteral::Property::GETTER: { |
@@ -2112,7 +2129,7 @@ |
__ push(r0); |
Load(value); |
__ CallRuntime(Runtime::kDefineAccessor, 4); |
- __ ldr(r0, MemOperand(sp, 0)); |
+ __ ldr(r0, frame_->Top()); |
break; |
} |
} |
@@ -2127,7 +2144,7 @@ |
__ mov(r0, Operand(node->literals())); |
__ push(r0); |
// Load the function of this frame. |
- __ ldr(r0, FunctionOperand()); |
+ __ ldr(r0, frame_->Function()); |
__ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); |
__ push(r0); |
__ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
@@ -2148,7 +2165,7 @@ |
__ pop(r0); |
// Fetch the object literal |
- __ ldr(r1, MemOperand(sp, 0)); |
+ __ ldr(r1, frame_->Top()); |
// Get the elements array. |
__ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); |
@@ -2271,7 +2288,7 @@ |
Handle<Code> stub = ComputeCallInitialize(args->length()); |
__ RecordPosition(node->position()); |
__ Call(stub, RelocInfo::CODE_TARGET_CONTEXT); |
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
+ __ ldr(cp, frame_->Context()); |
// Remove the function from the stack. |
__ pop(); |
__ push(r0); |
@@ -2318,7 +2335,7 @@ |
Handle<Code> stub = ComputeCallInitialize(args->length()); |
__ RecordPosition(node->position()); |
__ Call(stub, RelocInfo::CODE_TARGET); |
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
+ __ ldr(cp, frame_->Context()); |
// Remove the function from the stack. |
__ pop(); |
@@ -2335,7 +2352,7 @@ |
ref.GetValue(NOT_INSIDE_TYPEOF); // receiver |
// Pass receiver to called function. |
- __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize)); |
+ __ ldr(r0, frame_->Element(ref.size())); |
__ push(r0); |
// Call the function. |
CallWithArguments(args, node->position()); |
@@ -2383,7 +2400,7 @@ |
__ mov(r0, Operand(args->length())); |
// Load the function into r1 as per calling convention. |
- __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize)); |
+ __ ldr(r1, frame_->Element(args->length() + 1)); |
// Call the construct call builtin that handles allocation and |
// constructor invocation. |
@@ -2392,7 +2409,7 @@ |
RelocInfo::CONSTRUCT_CALL); |
// Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). |
- __ str(r0, MemOperand(sp, 0 * kPointerSize)); |
+ __ str(r0, frame_->Top()); |
} |
@@ -2565,7 +2582,7 @@ |
// Call the JS runtime function. |
Handle<Code> stub = ComputeCallInitialize(args->length()); |
__ Call(stub, RelocInfo::CODE_TARGET); |
- __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
+ __ ldr(cp, frame_->Context()); |
__ pop(); |
__ push(r0); |
} |
@@ -2727,7 +2744,9 @@ |
__ b(ne, &slow); |
// Postfix: Store the old value as the result. |
- if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize)); |
+ if (is_postfix) { |
+ __ str(r0, frame_->Element(target.size())); |
+ } |
// Perform optimistic increment/decrement. |
if (is_increment) { |
@@ -2754,7 +2773,7 @@ |
InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2); |
__ CallStub(&stub); |
// Store to result (on the stack). |
- __ str(r0, MemOperand(sp, target.size() * kPointerSize)); |
+ __ str(r0, frame_->Element(target.size())); |
} |
// Compute the new value by calling the right JavaScript native. |
@@ -2814,7 +2833,7 @@ |
} else { |
Label pop_and_continue, exit; |
- __ ldr(r0, MemOperand(sp, 0)); // dup the stack top |
+ __ ldr(r0, frame_->Top()); // dup the stack top |
__ push(r0); |
// Avoid popping the result if it converts to 'false' using the |
// standard ToBoolean() conversion as described in ECMA-262, |
@@ -2855,7 +2874,7 @@ |
} else { |
Label pop_and_continue, exit; |
- __ ldr(r0, MemOperand(sp, 0)); |
+ __ ldr(r0, frame_->Top()); |
__ push(r0); |
// Avoid popping the result if it converts to 'true' using the |
// standard ToBoolean() conversion as described in ECMA-262, |
@@ -2900,7 +2919,7 @@ |
void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
- __ ldr(r0, FunctionOperand()); |
+ __ ldr(r0, frame_->Function()); |
__ push(r0); |
} |