Index: src/codegen-ia32.cc |
=================================================================== |
--- src/codegen-ia32.cc (revision 483) |
+++ src/codegen-ia32.cc (working copy) |
@@ -35,9 +35,64 @@ |
namespace v8 { namespace internal { |
-#define TOS (Operand(esp, 0)) |
+#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(); |
+} |
+ |
+ |
+void VirtualFrame::AllocateLocals() { |
+ if (frame_local_count_ > 0) { |
+ Comment cmnt(masm_, "[ Allocate space for locals"); |
+ __ Set(eax, Immediate(Factory::undefined_value())); |
+ for (int i = 0; i < frame_local_count_; i++) { |
+ __ push(eax); |
+ } |
+ } |
+} |
+ |
+ |
+void VirtualFrame::Drop(int count) { |
+ ASSERT(count >= 0); |
+ if (count > 0) { |
+ __ add(Operand(esp), Immediate(count * kPointerSize)); |
+ } |
+} |
+ |
+ |
+void VirtualFrame::Pop(Register reg) { |
+ __ pop(reg); |
+} |
+ |
+ |
+void VirtualFrame::Pop(Operand operand) { |
+ __ pop(operand); |
+} |
+ |
+ |
+void VirtualFrame::Push(Register reg) { |
+ __ push(reg); |
+} |
+ |
+ |
+void VirtualFrame::Push(Operand operand) { |
+ __ push(operand); |
+} |
+ |
+ |
+void VirtualFrame::Push(Immediate immediate) { |
+ __ push(immediate); |
+} |
+ |
+ |
// ------------------------------------------------------------------------- |
// CodeGenState implementation. |
@@ -70,11 +125,9 @@ |
} |
-// ----------------------------------------------------------------------------- |
+// ------------------------------------------------------------------------- |
// CodeGenerator implementation |
-#define __ masm_-> |
- |
CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, |
bool is_eval) |
: is_eval_(is_eval), |
@@ -82,6 +135,7 @@ |
deferred_(8), |
masm_(new MacroAssembler(NULL, buffer_size)), |
scope_(NULL), |
+ frame_(NULL), |
cc_reg_(no_condition), |
state_(NULL), |
is_inside_try_(false), |
@@ -99,13 +153,17 @@ |
// Record the position for debugging purposes. |
__ RecordPosition(fun->start_position()); |
- Scope* scope = fun->scope(); |
ZoneList<Statement*>* body = fun->body(); |
// Initialize state. |
- { CodeGenState state(this); |
- scope_ = scope; |
- cc_reg_ = no_condition; |
+ ASSERT(scope_ == NULL); |
+ scope_ = fun->scope(); |
+ ASSERT(frame_ == NULL); |
+ VirtualFrame virtual_frame(this); |
+ frame_ = &virtual_frame; |
+ cc_reg_ = no_condition; |
+ { |
+ CodeGenState state(this); |
// Entry |
// stack: function, receiver, arguments, return address |
@@ -114,9 +172,7 @@ |
// edi: caller's parameter pointer |
// esi: callee's context |
- { Comment cmnt(masm_, "[ enter JS frame"); |
- EnterJSFrame(); |
- } |
+ frame_->Enter(); |
// tos: code slot |
#ifdef DEBUG |
if (strlen(FLAG_stop_at) > 0 && |
@@ -138,36 +194,32 @@ |
// Allocate arguments object. |
// The arguments object pointer needs to be saved in ecx, since we need |
// to store arguments into 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"); |
ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
- __ lea(eax, ReceiverOperand()); |
- __ push(FunctionOperand()); |
- __ push(eax); |
- __ push(Immediate(Smi::FromInt(scope->num_parameters()))); |
+ __ lea(eax, frame_->Receiver()); |
+ frame_->Push(frame_->Function()); |
+ frame_->Push(eax); |
+ frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters()))); |
__ CallStub(&stub); |
__ mov(ecx, Operand(eax)); |
arguments_object_allocated = true; |
} |
// Allocate space for locals and initialize them. |
- if (scope->num_stack_slots() > 0) { |
- Comment cmnt(masm_, "[ allocate space for locals"); |
- __ Set(eax, Immediate(Factory::undefined_value())); |
- for (int i = scope->num_stack_slots(); i-- > 0; ) __ push(eax); |
- } |
+ frame_->AllocateLocals(); |
- if (scope->num_heap_slots() > 0) { |
+ if (scope_->num_heap_slots() > 0) { |
Comment cmnt(masm_, "[ allocate local context"); |
// Save the arguments object pointer, if any. |
if (arguments_object_allocated && !arguments_object_saved) { |
- __ push(Operand(ecx)); |
+ frame_->Push(ecx); |
arguments_object_saved = true; |
} |
// Allocate local context. |
// Get outer context and create a new context based on it. |
- __ push(FunctionOperand()); |
+ frame_->Push(frame_->Function()); |
__ CallRuntime(Runtime::kNewContext, 1); // eax holds the result |
if (kDebug) { |
@@ -180,7 +232,7 @@ |
} |
// Update context local. |
- __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
+ __ mov(frame_->Context(), esi); |
// Restore the arguments array pointer, if any. |
} |
@@ -199,17 +251,17 @@ |
// 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) { |
// Save the arguments object pointer, if any. |
if (arguments_object_allocated && !arguments_object_saved) { |
- __ push(Operand(ecx)); |
+ frame_->Push(ecx); |
arguments_object_saved = true; |
} |
- ASSERT(!scope->is_global_scope()); // no parameters in global scope |
- __ mov(eax, ParameterOperand(i)); |
+ ASSERT(!scope_->is_global_scope()); // no parameters in global scope |
+ __ mov(eax, frame_->Parameter(i)); |
// Loads ecx with context; used below in RecordWrite. |
__ mov(SlotOperand(slot, ecx), eax); |
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
@@ -226,12 +278,12 @@ |
// 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); |
+ ASSERT(scope_->arguments() != NULL); |
+ ASSERT(scope_->arguments_shadow() != NULL); |
Comment cmnt(masm_, "[ store arguments object"); |
- { Reference shadow_ref(this, scope->arguments_shadow()); |
+ { Reference shadow_ref(this, scope_->arguments_shadow()); |
ASSERT(shadow_ref.is_slot()); |
- { Reference arguments_ref(this, scope->arguments()); |
+ { Reference arguments_ref(this, scope_->arguments()); |
ASSERT(arguments_ref.is_slot()); |
// If the newly-allocated arguments object is already on the |
// stack, we make use of the convenient property that references |
@@ -243,25 +295,25 @@ |
// the stack, we rely on the property that loading a |
// zero-sized reference will not clobber the ecx register. |
if (!arguments_object_saved) { |
- __ push(ecx); |
+ frame_->Push(ecx); |
} |
arguments_ref.SetValue(NOT_CONST_INIT); |
} |
shadow_ref.SetValue(NOT_CONST_INIT); |
} |
- __ pop(eax); // Value is no longer needed. |
+ frame_->Pop(eax); // Value is no longer needed. |
iposva
2008/10/10 12:53:02
If the value is really no longer needed the there
|
} |
// 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()) { |
+ if (scope_->HasIllegalRedeclaration()) { |
Comment cmnt(masm_, "[ illegal redeclarations"); |
- scope->VisitIllegalRedeclaration(this); |
+ scope_->VisitIllegalRedeclaration(this); |
} else { |
Comment cmnt(masm_, "[ declarations"); |
- ProcessDeclarations(scope->declarations()); |
+ ProcessDeclarations(scope_->declarations()); |
// Bail out if a stack-overflow exception occurred when |
// processing declarations. |
if (HasStackOverflow()) return; |
@@ -269,14 +321,14 @@ |
if (FLAG_trace) { |
__ CallRuntime(Runtime::kTraceEnter, 1); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
CheckStack(); |
// 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(); |
@@ -284,7 +336,7 @@ |
is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; |
if (should_trace) { |
__ CallRuntime(Runtime::kDebugTrace, 1); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
#endif |
VisitStatements(body); |
@@ -301,6 +353,7 @@ |
// Code generation state must be reset. |
scope_ = NULL; |
+ frame_ = NULL; |
ASSERT(!has_cc()); |
ASSERT(state_ == NULL); |
} |
@@ -319,13 +372,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 kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; |
- return Operand(ebp, kLocal0Offset - index * kPointerSize); |
- } |
+ case Slot::LOCAL: |
+ return frame_->Local(index); |
case Slot::CONTEXT: { |
// Follow the context chain if necessary. |
@@ -392,10 +442,10 @@ |
Label loaded, materialize_true; |
__ j(cc_reg_, &materialize_true); |
- __ push(Immediate(Factory::false_value())); |
+ frame_->Push(Immediate(Factory::false_value())); |
__ jmp(&loaded); |
__ bind(&materialize_true); |
- __ push(Immediate(Factory::true_value())); |
+ frame_->Push(Immediate(Factory::true_value())); |
__ bind(&loaded); |
cc_reg_ = no_condition; |
} |
@@ -410,7 +460,7 @@ |
// reincarnate "true", if necessary |
if (true_target.is_linked()) { |
__ bind(&true_target); |
- __ push(Immediate(Factory::true_value())); |
+ frame_->Push(Immediate(Factory::true_value())); |
} |
// if both "true" and "false" need to be reincarnated, |
// jump across code for "false" |
@@ -419,7 +469,7 @@ |
// reincarnate "false", if necessary |
if (false_target.is_linked()) { |
__ bind(&false_target); |
- __ push(Immediate(Factory::false_value())); |
+ frame_->Push(Immediate(Factory::false_value())); |
} |
// everything is loaded at this point |
__ bind(&loaded); |
@@ -429,7 +479,7 @@ |
void CodeGenerator::LoadGlobal() { |
- __ push(GlobalObject()); |
+ frame_->Push(GlobalObject()); |
} |
@@ -514,12 +564,12 @@ |
if (size <= 0) { |
// Do nothing. No popping is necessary. |
} else if (size == 1) { |
- __ pop(eax); |
- __ mov(TOS, eax); |
+ frame_->Pop(eax); |
+ __ mov(frame_->Top(), eax); |
} else { |
- __ pop(eax); |
- __ add(Operand(esp), Immediate(size * kPointerSize)); |
- __ push(eax); |
+ frame_->Pop(eax); |
+ frame_->Drop(size); |
+ frame_->Push(eax); |
} |
} |
@@ -543,7 +593,7 @@ |
Comment cmnt(masm_, "[ ToBoolean"); |
// The value to convert should be popped from the stack. |
- __ pop(eax); |
+ frame_->Pop(eax); |
// Fast case checks. |
@@ -567,7 +617,7 @@ |
__ j(zero, true_target); |
// Call the stub for all other cases. |
- __ push(eax); // Undo the pop(eax) from above. |
+ frame_->Push(eax); // Undo the pop(eax) from above. |
ToBooleanStub stub; |
__ CallStub(&stub); |
// Convert result (eax) to condition code. |
@@ -662,15 +712,15 @@ |
case Token::MOD: { |
GenericBinaryOpStub stub(op, overwrite_mode); |
__ CallStub(&stub); |
- __ push(eax); |
+ frame_->Push(eax); |
break; |
} |
case Token::BIT_OR: |
case Token::BIT_AND: |
case Token::BIT_XOR: { |
Label slow, exit; |
- __ pop(eax); // get y |
- __ pop(edx); // get x |
+ frame_->Pop(eax); // get y |
+ frame_->Pop(edx); // get x |
__ mov(ecx, Operand(edx)); // Prepare smi check. |
// tag check |
__ or_(ecx, Operand(eax)); // ecx = x | y; |
@@ -685,20 +735,20 @@ |
} |
__ jmp(&exit); |
__ bind(&slow); |
- __ push(edx); // restore stack slots |
- __ push(eax); |
+ frame_->Push(edx); // restore stack slots |
+ frame_->Push(eax); |
GenericBinaryOpStub stub(op, overwrite_mode); |
__ CallStub(&stub); |
__ bind(&exit); |
- __ push(eax); // push the result to the stack |
+ frame_->Push(eax); // push the result to the stack |
break; |
} |
case Token::SHL: |
case Token::SHR: |
case Token::SAR: { |
Label slow, exit; |
- __ pop(edx); // get y |
- __ pop(eax); // get x |
+ frame_->Pop(edx); // get y |
+ frame_->Pop(eax); // get x |
// tag check |
__ mov(ecx, Operand(edx)); |
__ or_(ecx, Operand(eax)); // ecx = x | y; |
@@ -743,19 +793,19 @@ |
__ jmp(&exit); |
// slow case |
__ bind(&slow); |
- __ push(eax); // restore stack |
- __ push(edx); |
+ frame_->Push(eax); // restore stack |
+ frame_->Push(edx); |
GenericBinaryOpStub stub(op, overwrite_mode); |
__ CallStub(&stub); |
__ bind(&exit); |
- __ push(eax); |
+ frame_->Push(eax); |
break; |
} |
case Token::COMMA: { |
// simply discard left value |
- __ pop(eax); |
- __ add(Operand(esp), Immediate(kPointerSize)); |
- __ push(eax); |
+ frame_->Pop(eax); |
+ frame_->Drop(1); |
+ frame_->Push(eax); |
break; |
} |
default: UNREACHABLE(); |
@@ -896,7 +946,7 @@ |
// Undo the optimistic sub operation and call the shared stub. |
__ add(eax, Operand(tos_reg_)); |
__ push(eax); |
- __ push(Operand(tos_reg_)); |
+ __ push(tos_reg_); |
GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_); |
__ CallStub(&igostub); |
} |
@@ -908,9 +958,9 @@ |
void CodeGenerator::SmiOperation(Token::Value op, |
- Handle<Object> value, |
- bool reversed, |
- OverwriteMode overwrite_mode) { |
+ Handle<Object> value, |
+ bool reversed, |
+ OverwriteMode overwrite_mode) { |
// 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 |
@@ -934,19 +984,19 @@ |
deferred = new DeferredInlinedSmiAddReversed(this, int_value, |
overwrite_mode); |
} |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ add(Operand(eax), Immediate(value)); |
__ j(overflow, deferred->enter(), not_taken); |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(not_zero, deferred->enter(), not_taken); |
__ bind(deferred->exit()); |
- __ push(eax); |
+ frame_->Push(eax); |
break; |
} |
case Token::SUB: { |
DeferredCode* deferred = NULL; |
- __ pop(eax); |
+ frame_->Pop(eax); |
if (!reversed) { |
deferred = new DeferredInlinedSmiSub(this, int_value, overwrite_mode); |
__ sub(Operand(eax), Immediate(value)); |
@@ -960,44 +1010,44 @@ |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(not_zero, deferred->enter(), not_taken); |
__ bind(deferred->exit()); |
- __ push(eax); |
+ frame_->Push(eax); |
break; |
} |
case Token::SAR: { |
if (reversed) { |
- __ pop(eax); |
- __ push(Immediate(value)); |
- __ push(eax); |
+ frame_->Pop(eax); |
+ frame_->Push(Immediate(value)); |
+ frame_->Push(eax); |
GenericBinaryOperation(op, overwrite_mode); |
} else { |
int shift_value = int_value & 0x1f; // only least significant 5 bits |
DeferredCode* deferred = |
new DeferredInlinedSmiOperation(this, Token::SAR, shift_value, |
overwrite_mode); |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(not_zero, deferred->enter(), not_taken); |
__ sar(eax, shift_value); |
__ and_(eax, ~kSmiTagMask); |
__ bind(deferred->exit()); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
break; |
} |
case Token::SHR: { |
if (reversed) { |
- __ pop(eax); |
- __ push(Immediate(value)); |
- __ push(eax); |
+ frame_->Pop(eax); |
+ frame_->Push(Immediate(value)); |
+ frame_->Push(eax); |
GenericBinaryOperation(op, overwrite_mode); |
} else { |
int shift_value = int_value & 0x1f; // only least significant 5 bits |
DeferredCode* deferred = |
new DeferredInlinedSmiOperation(this, Token::SHR, shift_value, |
overwrite_mode); |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask)); |
__ mov(ebx, Operand(eax)); |
__ j(not_zero, deferred->enter(), not_taken); |
@@ -1009,23 +1059,23 @@ |
ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
__ lea(eax, Operand(ebx, times_2, kSmiTag)); |
__ bind(deferred->exit()); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
break; |
} |
case Token::SHL: { |
if (reversed) { |
- __ pop(eax); |
- __ push(Immediate(value)); |
- __ push(eax); |
+ frame_->Pop(eax); |
+ frame_->Push(Immediate(value)); |
+ frame_->Push(eax); |
GenericBinaryOperation(op, overwrite_mode); |
} else { |
int shift_value = int_value & 0x1f; // only least significant 5 bits |
DeferredCode* deferred = |
new DeferredInlinedSmiOperation(this, Token::SHL, shift_value, |
overwrite_mode); |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask)); |
__ mov(ebx, Operand(eax)); |
__ j(not_zero, deferred->enter(), not_taken); |
@@ -1038,7 +1088,7 @@ |
ASSERT(kSmiTagSize == times_2); // adjust code if not the case |
__ lea(eax, Operand(ebx, times_2, kSmiTag)); |
__ bind(deferred->exit()); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
break; |
} |
@@ -1054,7 +1104,7 @@ |
deferred = new DeferredInlinedSmiOperationReversed(this, op, int_value, |
overwrite_mode); |
} |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(not_zero, deferred->enter(), not_taken); |
if (op == Token::BIT_AND) { |
@@ -1066,17 +1116,17 @@ |
__ or_(Operand(eax), Immediate(value)); |
} |
__ bind(deferred->exit()); |
- __ push(eax); |
+ frame_->Push(eax); |
break; |
} |
default: { |
if (!reversed) { |
- __ push(Immediate(value)); |
+ frame_->Push(Immediate(value)); |
} else { |
- __ pop(eax); |
- __ push(Immediate(value)); |
- __ push(eax); |
+ frame_->Pop(eax); |
+ frame_->Push(Immediate(value)); |
+ frame_->Push(eax); |
} |
GenericBinaryOperation(op, overwrite_mode); |
break; |
@@ -1120,11 +1170,11 @@ |
// Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
if (cc == greater || cc == less_equal) { |
cc = ReverseCondition(cc); |
- __ pop(edx); |
- __ pop(eax); |
+ frame_->Pop(edx); |
+ frame_->Pop(eax); |
} else { |
- __ pop(eax); |
- __ pop(edx); |
+ frame_->Pop(eax); |
+ frame_->Pop(edx); |
} |
// Check for the smi case. |
@@ -1195,7 +1245,7 @@ |
SmiComparisonDeferred* deferred = |
new SmiComparisonDeferred(this, cc, strict, int_value); |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(not_zero, deferred->enter(), not_taken); |
// Test smi equality by pointer comparison. |
@@ -1240,8 +1290,8 @@ |
__ CallStub(&call_function); |
// Restore context and pop function from the stack. |
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
- __ mov(TOS, eax); |
+ __ mov(esi, frame_->Context()); |
+ __ mov(frame_->Top(), eax); |
} |
@@ -1277,9 +1327,9 @@ |
void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
- __ push(Immediate(pairs)); |
- __ push(Operand(esi)); |
- __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
+ frame_->Push(Immediate(pairs)); |
+ frame_->Push(esi); |
+ frame_->Push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
__ CallRuntime(Runtime::kDeclareGlobals, 3); |
// Return value is ignored. |
} |
@@ -1299,22 +1349,22 @@ |
// during variable resolution and must have mode DYNAMIC. |
ASSERT(var->mode() == Variable::DYNAMIC); |
// For now, just do a runtime call. |
- __ push(Operand(esi)); |
- __ push(Immediate(var->name())); |
+ frame_->Push(esi); |
+ frame_->Push(Immediate(var->name())); |
// Declaration nodes are always introduced in one of two modes. |
ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST); |
PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY; |
- __ push(Immediate(Smi::FromInt(attr))); |
+ frame_->Push(Immediate(Smi::FromInt(attr))); |
// 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) { |
- __ push(Immediate(Factory::the_hole_value())); |
+ frame_->Push(Immediate(Factory::the_hole_value())); |
} else if (node->fun() != NULL) { |
Load(node->fun()); |
} else { |
- __ push(Immediate(0)); // no initial value! |
+ frame_->Push(Immediate(0)); // no initial value! |
} |
__ CallRuntime(Runtime::kDeclareContextSlot, 4); |
// Ignore the return value (declarations are statements). |
@@ -1341,7 +1391,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 that it is a zero-sized reference. |
- __ pop(eax); // Pop(no_reg); |
+ frame_->Pop(eax); // Pop(no_reg); |
iposva
2008/10/10 12:53:02
Another potential use of Pop()...
|
} |
} |
@@ -1352,7 +1402,7 @@ |
Expression* expression = node->expression(); |
expression->MarkAsStatement(); |
Load(expression); |
- __ pop(eax); // remove the lingering expression result from the top of stack |
+ frame_->Pop(eax); // remove the lingering expression result from the top of stack |
iposva
2008/10/10 12:53:02
And another potential use of Pop()...
|
} |
@@ -1414,7 +1464,7 @@ |
} else { |
// No cc value set up, that means the boolean was pushed. |
// Pop it again, since it is not going to be used. |
- __ pop(eax); |
+ frame_->Pop(eax); |
} |
} |
@@ -1424,10 +1474,8 @@ |
void CodeGenerator::CleanStack(int num_bytes) { |
- ASSERT(num_bytes >= 0); |
- if (num_bytes > 0) { |
- __ add(Operand(esp), Immediate(num_bytes)); |
- } |
+ ASSERT(num_bytes % kPointerSize == 0); |
+ frame_->Drop(num_bytes / kPointerSize); |
} |
@@ -1453,7 +1501,7 @@ |
Load(node->expression()); |
// Move the function result into eax |
- __ pop(eax); |
+ frame_->Pop(eax); |
// If we're inside a try statement or the return instruction |
// sequence has been generated, we just jump to that |
@@ -1464,7 +1512,7 @@ |
} else { |
__ bind(&function_return_); |
if (FLAG_trace) { |
- __ push(eax); // undo the pop(eax) from above |
+ frame_->Push(eax); // undo the pop(eax) from above |
__ CallRuntime(Runtime::kTraceExit, 1); |
} |
@@ -1474,7 +1522,7 @@ |
// Leave the frame and return popping the arguments and the |
// receiver. |
- ExitJSFrame(); |
+ frame_->Exit(); |
__ ret((scope_->num_parameters() + 1) * kPointerSize); |
// Check that the size of the code used for returning matches what is |
@@ -1501,7 +1549,7 @@ |
} |
// Update context local. |
- __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
+ __ mov(frame_->Context(), esi); |
} |
@@ -1510,7 +1558,7 @@ |
// Pop context. |
__ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
// Update context local. |
- __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
+ __ mov(frame_->Context(), esi); |
} |
int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
@@ -1533,7 +1581,7 @@ |
// placeholders, and fill in the addresses after the labels have been |
// bound. |
- __ pop(eax); // supposed smi |
+ frame_->Pop(eax); // supposed smi |
// check range of value, if outside [0..length-1] jump to default/end label. |
ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
if (min_index != 0) { |
@@ -1599,8 +1647,8 @@ |
} else { |
__ bind(&next); |
next.Unuse(); |
- __ mov(eax, TOS); |
- __ push(eax); // duplicate TOS |
+ __ mov(eax, frame_->Top()); |
+ frame_->Push(eax); // duplicate TOS |
Load(clause->label()); |
Comparison(equal, true); |
Branch(false, &next); |
@@ -1608,7 +1656,7 @@ |
// Entering the case statement for the first time. Remove the switch value |
// from the stack. |
- __ pop(eax); |
+ frame_->Pop(eax); |
// Generate code for the body. |
// This is also the target for the fall through from the previous case's |
@@ -1627,7 +1675,7 @@ |
__ jmp(&default_case); |
} else { |
// Remove the switch value from the stack. |
- __ pop(eax); |
+ frame_->Pop(eax); |
} |
__ bind(&fall_through); |
@@ -1723,7 +1771,7 @@ |
// Both SpiderMonkey and kjs ignore null and undefined in contrast |
// to the specification. 12.6.4 mandates a call to ToObject. |
- __ pop(eax); |
+ frame_->Pop(eax); |
// eax: value to be iterated over |
__ cmp(eax, Factory::undefined_value()); |
@@ -1748,7 +1796,7 @@ |
__ j(above_equal, &jsobject); |
__ bind(&primitive); |
- __ push(eax); |
+ frame_->Push(eax); |
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
// function call returns the value in eax, which is where we want it below |
@@ -1757,9 +1805,9 @@ |
// Get the set of properties (as a FixedArray or Map). |
// eax: value to be iterated over |
- __ push(eax); // push the object being iterated over (slot 4) |
+ frame_->Push(eax); // push the object being iterated over (slot 4) |
- __ push(eax); // push the Object (slot 4) for the runtime call |
+ frame_->Push(eax); // push the Object (slot 4) for the runtime call |
__ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
// If we got a Map, we can do a fast modification check. |
@@ -1780,26 +1828,26 @@ |
// Get the cache from the bridge array. |
__ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
- __ push(eax); // <- slot 3 |
- __ push(Operand(edx)); // <- slot 2 |
+ frame_->Push(eax); // <- slot 3 |
+ frame_->Push(edx); // <- slot 2 |
__ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); |
__ shl(eax, kSmiTagSize); |
- __ push(eax); // <- slot 1 |
- __ push(Immediate(Smi::FromInt(0))); // <- slot 0 |
+ frame_->Push(eax); // <- slot 1 |
+ frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 |
__ jmp(&entry); |
__ bind(&fixed_array); |
// eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) |
- __ push(Immediate(Smi::FromInt(0))); // <- slot 3 |
- __ push(eax); // <- slot 2 |
+ frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 3 |
+ frame_->Push(eax); // <- slot 2 |
// Push the length of the array and the initial index onto the stack. |
__ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); |
__ shl(eax, kSmiTagSize); |
- __ push(eax); // <- slot 1 |
- __ push(Immediate(Smi::FromInt(0))); // <- slot 0 |
+ frame_->Push(eax); // <- slot 1 |
+ frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 |
__ jmp(&entry); |
// Body. |
@@ -1809,39 +1857,39 @@ |
// Next. |
__ bind(node->continue_target()); |
__ bind(&next); |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ add(Operand(eax), Immediate(Smi::FromInt(1))); |
- __ push(eax); |
+ frame_->Push(eax); |
// Condition. |
__ bind(&entry); |
- __ mov(eax, Operand(esp, 0 * kPointerSize)); // load the current count |
- __ cmp(eax, Operand(esp, kPointerSize)); // compare to the array length |
+ __ mov(eax, frame_->Element(0)); // load the current count |
+ __ cmp(eax, frame_->Element(1)); // compare to the array length |
__ j(above_equal, &cleanup); |
// Get the i'th entry of the array. |
- __ mov(edx, Operand(esp, 2 * kPointerSize)); |
+ __ mov(edx, frame_->Element(2)); |
__ mov(ebx, Operand(edx, eax, times_2, |
FixedArray::kHeaderSize - kHeapObjectTag)); |
// Get the expected map from the stack or a zero map in the |
// permanent slow case eax: current iteration count ebx: i'th entry |
// of the enum cache |
- __ mov(edx, Operand(esp, 3 * kPointerSize)); |
+ __ mov(edx, frame_->Element(3)); |
// Check if the expected map still matches that of the enumerable. |
// If not, we have to filter the key. |
// eax: current iteration count |
// ebx: i'th entry of the enum cache |
// edx: expected map value |
- __ mov(ecx, Operand(esp, 4 * kPointerSize)); |
+ __ mov(ecx, frame_->Element(4)); |
__ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); |
__ cmp(ecx, Operand(edx)); |
__ j(equal, &end_del_check); |
// Convert the entry to a string (or null if it isn't a property anymore). |
- __ push(Operand(esp, 4 * kPointerSize)); // push enumerable |
- __ push(Operand(ebx)); // push entry |
+ frame_->Push(frame_->Element(4)); // push enumerable |
+ frame_->Push(ebx); // push entry |
__ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
__ mov(ebx, Operand(eax)); |
@@ -1854,11 +1902,11 @@ |
// Store the entry in the 'each' expression and take another spin in the loop. |
// edx: i'th entry of the enum cache (or string there of) |
- __ push(ebx); |
+ frame_->Push(ebx); |
{ Reference each(this, node->each()); |
if (!each.is_illegal()) { |
if (each.size() > 0) { |
- __ push(Operand(esp, kPointerSize * each.size())); |
+ frame_->Push(frame_->Element(each.size())); |
} |
// If the reference was to a slot we rely on the convenient property |
// that it doesn't matter whether a value (eg, ebx pushed above) is |
@@ -1870,20 +1918,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(eax); |
+ frame_->Pop(eax); |
} |
} |
} |
// Discard the i'th entry pushed above or else the remainder of the |
// reference, whichever is currently on top of the stack. |
- __ pop(eax); |
+ frame_->Pop(eax); |
CheckStack(); // TODO(1222600): ignore if body contains calls. |
__ jmp(&loop); |
// Cleanup. |
__ bind(&cleanup); |
__ bind(node->break_target()); |
- __ add(Operand(esp), Immediate(5 * kPointerSize)); |
+ frame_->Drop(5); |
// Exit. |
__ bind(&exit); |
@@ -1899,7 +1947,7 @@ |
__ call(&try_block); |
// --- Catch block --- |
- __ push(eax); |
+ frame_->Push(eax); |
// Store the caught exception in the catch variable. |
{ Reference ref(this, node->catch_var()); |
@@ -1911,7 +1959,7 @@ |
} |
// Remove the exception from the stack. |
- __ pop(edx); |
+ frame_->Pop(edx); |
VisitStatements(node->catch_block()->statements()); |
__ jmp(&exit); |
@@ -1922,7 +1970,7 @@ |
__ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); |
// TODO(1222589): remove the reliance of PushTryHandler on a cached TOS |
- __ push(eax); // |
+ frame_->Push(eax); // |
// Introduce shadow labels for all escapes from the try block, |
// including returns. We should probably try to unify the escaping |
@@ -1960,9 +2008,9 @@ |
} |
// Unlink from try chain. |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ mov(Operand::StaticVariable(handler_address), eax); // TOS == next_sp |
- __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); |
+ frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
// next_sp popped. |
if (nof_unlinks > 0) __ jmp(&exit); |
@@ -1979,9 +2027,8 @@ |
StackHandlerConstants::kAddressDisplacement; |
__ lea(esp, Operand(edx, kNextOffset)); |
- __ pop(Operand::StaticVariable(handler_address)); |
- __ add(Operand(esp), |
- Immediate(StackHandlerConstants::kSize - kPointerSize)); |
+ frame_->Pop(Operand::StaticVariable(handler_address)); |
+ frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
// next_sp popped. |
__ jmp(shadows[i]->shadowed()); |
} |
@@ -2003,7 +2050,7 @@ |
__ call(&try_block); |
- __ push(eax); |
+ frame_->Push(eax); |
// In case of thrown exceptions, this is where we continue. |
__ Set(ecx, Immediate(Smi::FromInt(THROWING))); |
__ jmp(&finally_block); |
@@ -2014,7 +2061,7 @@ |
__ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); |
// TODO(1222589): remove the reliance of PushTryHandler on a cached TOS |
- __ push(eax); |
+ frame_->Push(eax); |
// Introduce shadow labels for all escapes from the try block, |
// including returns. We should probably try to unify the escaping |
@@ -2041,7 +2088,7 @@ |
} |
// Set the state on the stack to FALLING. |
- __ push(Immediate(Factory::undefined_value())); // fake TOS |
+ frame_->Push(Immediate(Factory::undefined_value())); // fake TOS |
__ Set(ecx, Immediate(Smi::FromInt(FALLING))); |
if (nof_unlinks > 0) __ jmp(&unlink); |
@@ -2051,10 +2098,10 @@ |
__ bind(shadows[i]); |
if (shadows[i]->shadowed() == &function_return_) { |
// Materialize the return value on the stack. |
- __ push(eax); |
+ frame_->Push(eax); |
} else { |
// Fake TOS for break and continue. |
- __ push(Immediate(Factory::undefined_value())); |
+ frame_->Push(Immediate(Factory::undefined_value())); |
} |
__ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); |
__ jmp(&unlink); |
@@ -2065,23 +2112,23 @@ |
__ bind(&unlink); |
// Reload sp from the top handler, because some statements that we |
// break from (eg, for...in) may have left stuff on the stack. |
- __ pop(eax); // preserve the TOS in a register across stack manipulation |
+ frame_->Pop(eax); // preserve the TOS in a register across stack manipulation |
ExternalReference handler_address(Top::k_handler_address); |
__ mov(edx, Operand::StaticVariable(handler_address)); |
const int kNextOffset = StackHandlerConstants::kNextOffset + |
StackHandlerConstants::kAddressDisplacement; |
__ lea(esp, Operand(edx, kNextOffset)); |
- __ pop(Operand::StaticVariable(handler_address)); |
- __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); |
+ frame_->Pop(Operand::StaticVariable(handler_address)); |
+ frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
// next_sp popped. |
- __ push(eax); // preserve the TOS in a register across stack manipulation |
+ frame_->Push(eax); // preserve the TOS in a register across stack manipulation |
// --- Finally block --- |
__ bind(&finally_block); |
// Push the state on the stack. |
- __ push(ecx); |
+ frame_->Push(ecx); |
// We keep two elements on the stack - the (possibly faked) result |
// and the state - while evaluating the finally block. Record it, so |
@@ -2094,8 +2141,8 @@ |
VisitStatements(node->finally_block()->statements()); |
// Restore state and return value or faked TOS. |
- __ pop(ecx); |
- __ pop(eax); |
+ frame_->Pop(ecx); |
+ frame_->Pop(eax); |
break_stack_height_ -= kFinallyStackSize; |
// Generate code that jumps to the right destination for all used |
@@ -2112,7 +2159,7 @@ |
__ j(not_equal, &exit); |
// Rethrow exception. |
- __ push(eax); // undo pop from above |
+ frame_->Push(eax); // undo pop from above |
__ CallRuntime(Runtime::kReThrow, 1); |
// Done. |
@@ -2124,7 +2171,7 @@ |
Comment cmnt(masm_, "[ DebuggerStatement"); |
RecordStatementPosition(node); |
__ CallRuntime(Runtime::kDebugBreak, 1); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
@@ -2132,12 +2179,12 @@ |
ASSERT(boilerplate->IsBoilerplate()); |
// Push the boilerplate on the stack. |
- __ push(Immediate(boilerplate)); |
+ frame_->Push(Immediate(boilerplate)); |
// Create a new closure. |
- __ push(esi); |
+ frame_->Push(esi); |
__ CallRuntime(Runtime::kNewClosure, 2); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
@@ -2178,15 +2225,15 @@ |
ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
// For now, just do a runtime call. |
- __ push(esi); |
- __ push(Immediate(slot->var()->name())); |
+ frame_->Push(esi); |
+ frame_->Push(Immediate(slot->var()->name())); |
if (typeof_state == INSIDE_TYPEOF) { |
__ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
} else { |
__ CallRuntime(Runtime::kLoadContextSlot, 2); |
} |
- __ push(eax); |
+ frame_->Push(eax); |
} else { |
// Note: We would like to keep the assert below, but it fires because of |
@@ -2203,9 +2250,9 @@ |
__ j(not_equal, &exit); |
__ mov(eax, Factory::undefined_value()); |
__ bind(&exit); |
- __ push(eax); |
+ frame_->Push(eax); |
} else { |
- __ push(SlotOperand(slot, ecx)); |
+ frame_->Push(SlotOperand(slot, ecx)); |
} |
} |
} |
@@ -2239,9 +2286,9 @@ |
int bits = reinterpret_cast<int>(*node->handle()); |
__ mov(eax, bits & 0x0000FFFF); |
__ xor_(eax, bits & 0xFFFF0000); |
- __ push(eax); |
+ frame_->Push(eax); |
} else { |
- __ push(Immediate(node->handle())); |
+ frame_->Push(Immediate(node->handle())); |
} |
} |
@@ -2282,7 +2329,7 @@ |
// Retrieve the literal array and check the allocated entry. |
// Load the function of this activation. |
- __ mov(ecx, FunctionOperand()); |
+ __ mov(ecx, frame_->Function()); |
// Load the literals array of the function. |
__ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
@@ -2299,7 +2346,7 @@ |
__ bind(deferred->exit()); |
// Push the literal. |
- __ push(ebx); |
+ frame_->Push(ebx); |
} |
@@ -2325,7 +2372,7 @@ |
// the literal. |
// Literal array (0). |
- __ push(Operand(ecx)); |
+ __ push(ecx); |
// Literal index (1). |
__ push(Immediate(Smi::FromInt(node_->literal_index()))); |
// Constant properties (2). |
@@ -2342,7 +2389,7 @@ |
// Retrieve the literal array and check the allocated entry. |
// Load the function of this activation. |
- __ mov(ecx, FunctionOperand()); |
+ __ mov(ecx, frame_->Function()); |
// Load the literals array of the function. |
__ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
@@ -2359,11 +2406,11 @@ |
__ bind(deferred->exit()); |
// Push the literal. |
- __ push(ebx); |
+ frame_->Push(ebx); |
// Clone the boilerplate object. |
__ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); |
// Push the new cloned literal object as the result. |
- __ push(eax); |
+ frame_->Push(eax); |
for (int i = 0; i < node->properties()->length(); i++) { |
@@ -2374,21 +2421,21 @@ |
Handle<Object> key(property->key()->handle()); |
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
if (key->IsSymbol()) { |
- __ mov(eax, TOS); |
- __ push(eax); |
+ __ mov(eax, frame_->Top()); |
+ frame_->Push(eax); |
Load(property->value()); |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ Set(ecx, Immediate(key)); |
__ call(ic, RelocInfo::CODE_TARGET); |
- __ add(Operand(esp), Immediate(kPointerSize)); |
+ frame_->Drop(1); |
// Ignore result. |
break; |
} |
// Fall through |
} |
case ObjectLiteral::Property::PROTOTYPE: { |
- __ mov(eax, TOS); |
- __ push(eax); |
+ __ mov(eax, frame_->Top()); |
+ frame_->Push(eax); |
Load(property->key()); |
Load(property->value()); |
__ CallRuntime(Runtime::kSetProperty, 3); |
@@ -2398,10 +2445,10 @@ |
case ObjectLiteral::Property::SETTER: { |
// Duplicate the resulting object on the stack. The runtime |
// function will pop the three arguments passed in. |
- __ mov(eax, TOS); |
- __ push(eax); |
+ __ mov(eax, frame_->Top()); |
+ frame_->Push(eax); |
Load(property->key()); |
- __ push(Immediate(Smi::FromInt(1))); |
+ frame_->Push(Immediate(Smi::FromInt(1))); |
Load(property->value()); |
__ CallRuntime(Runtime::kDefineAccessor, 4); |
// Ignore result. |
@@ -2410,10 +2457,10 @@ |
case ObjectLiteral::Property::GETTER: { |
// Duplicate the resulting object on the stack. The runtime |
// function will pop the three arguments passed in. |
- __ mov(eax, TOS); |
- __ push(eax); |
+ __ mov(eax, frame_->Top()); |
+ frame_->Push(eax); |
Load(property->key()); |
- __ push(Immediate(Smi::FromInt(0))); |
+ frame_->Push(Immediate(Smi::FromInt(0))); |
Load(property->value()); |
__ CallRuntime(Runtime::kDefineAccessor, 4); |
// Ignore result. |
@@ -2429,16 +2476,16 @@ |
Comment cmnt(masm_, "[ ArrayLiteral"); |
// Call runtime to create the array literal. |
- __ push(Immediate(node->literals())); |
+ frame_->Push(Immediate(node->literals())); |
// Load the function of this frame. |
- __ mov(ecx, FunctionOperand()); |
+ __ mov(ecx, frame_->Function()); |
// Load the literals array of the function. |
__ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
- __ push(ecx); |
+ frame_->Push(ecx); |
__ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
// Push the resulting array literal on the stack. |
- __ push(eax); |
+ frame_->Push(eax); |
// Generate code to set the elements in the array that are not |
// literals. |
@@ -2452,9 +2499,9 @@ |
Load(value); |
// Get the value off the stack. |
- __ pop(eax); |
+ frame_->Pop(eax); |
// Fetch the object literal while leaving on the stack. |
- __ mov(ecx, TOS); |
+ __ mov(ecx, frame_->Top()); |
// Get the elements array. |
__ mov(ecx, FieldOperand(ecx, JSObject::kElementsOffset)); |
@@ -2524,7 +2571,7 @@ |
Load(node->exception()); |
__ RecordPosition(node->position()); |
__ CallRuntime(Runtime::kThrow, 1); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
@@ -2563,7 +2610,7 @@ |
// ---------------------------------- |
// Push the name of the function and the receiver onto the stack. |
- __ push(Immediate(var->name())); |
+ frame_->Push(Immediate(var->name())); |
LoadGlobal(); |
// Load the arguments. |
@@ -2575,10 +2622,10 @@ |
Handle<Code> stub = ComputeCallInitialize(args->length()); |
__ RecordPosition(node->position()); |
__ call(stub, RelocInfo::CODE_TARGET_CONTEXT); |
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
+ __ mov(esi, frame_->Context()); |
// Overwrite the function on the stack with the result. |
- __ mov(TOS, eax); |
+ __ mov(frame_->Top(), eax); |
} else if (var != NULL && var->slot() != NULL && |
var->slot()->type() == Slot::LOOKUP) { |
@@ -2587,14 +2634,14 @@ |
// ---------------------------------- |
// Load the function |
- __ push(Operand(esi)); |
- __ push(Immediate(var->name())); |
+ frame_->Push(esi); |
+ frame_->Push(Immediate(var->name())); |
__ CallRuntime(Runtime::kLoadContextSlot, 2); |
// eax: slot value; edx: receiver |
// Load the receiver. |
- __ push(eax); |
- __ push(edx); |
+ frame_->Push(eax); |
+ frame_->Push(edx); |
// Call the function. |
CallWithArguments(args, node->position()); |
@@ -2609,7 +2656,7 @@ |
// ------------------------------------------------------------------ |
// Push the name of the function and the receiver onto the stack. |
- __ push(Immediate(literal->handle())); |
+ frame_->Push(Immediate(literal->handle())); |
Load(property->obj()); |
// Load the arguments. |
@@ -2619,10 +2666,10 @@ |
Handle<Code> stub = ComputeCallInitialize(args->length()); |
__ RecordPosition(node->position()); |
__ call(stub, RelocInfo::CODE_TARGET); |
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
+ __ mov(esi, frame_->Context()); |
// Overwrite the function on the stack with the result. |
- __ mov(TOS, eax); |
+ __ mov(frame_->Top(), eax); |
} else { |
// ------------------------------------------- |
@@ -2635,7 +2682,7 @@ |
// Pass receiver to called function. |
// The reference's size is non-negative. |
- __ push(Operand(esp, ref.size() * kPointerSize)); |
+ frame_->Push(frame_->Element(ref.size())); |
// Call the function. |
CallWithArguments(args, node->position()); |
@@ -2683,21 +2730,22 @@ |
// Load the function into temporary function slot as per calling |
// convention. |
- __ mov(edi, Operand(esp, (args->length() + 1) * kPointerSize)); |
+ __ mov(edi, frame_->Element(args->length() + 1)); |
// Call the construct call builtin that handles allocation and |
// constructor invocation. |
__ RecordPosition(node->position()); |
__ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), |
RelocInfo::CONSTRUCT_CALL); |
- __ mov(TOS, eax); // discard the function and "push" the newly created object |
+ // Discard the function and "push" the newly created object. |
+ __ mov(frame_->Top(), eax); |
} |
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
ASSERT(args->length() == 1); |
Load(args->at(0)); |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask)); |
cc_reg_ = zero; |
} |
@@ -2706,7 +2754,7 @@ |
void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
ASSERT(args->length() == 1); |
Load(args->at(0)); |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
cc_reg_ = zero; |
} |
@@ -2731,7 +2779,7 @@ |
// Load the string into eax. |
Load(args->at(0)); |
- __ pop(eax); |
+ frame_->Pop(eax); |
// If the receiver is a smi return undefined. |
ASSERT(kSmiTag == 0); |
__ test(eax, Immediate(kSmiTagMask)); |
@@ -2739,7 +2787,7 @@ |
// Load the index into ebx. |
Load(args->at(1)); |
- __ pop(ebx); |
+ frame_->Pop(ebx); |
// Check for negative or non-smi index. |
ASSERT(kSmiTag == 0); |
@@ -2810,7 +2858,7 @@ |
__ bind(&got_char_code); |
ASSERT(kSmiTag == 0); |
__ shl(eax, kSmiTagSize); |
- __ push(eax); |
+ frame_->Push(eax); |
__ jmp(&end); |
@@ -2838,7 +2886,7 @@ |
__ jmp(&try_again_with_new_string); |
__ bind(&slow_case); |
- __ push(Immediate(Factory::undefined_value())); |
+ frame_->Push(Immediate(Factory::undefined_value())); |
__ bind(&end); |
} |
@@ -2852,7 +2900,7 @@ |
// object is a smi. This can't be done with the usual test opcode so |
// we copy the object to ecx and do some destructive ops on it that |
// result in the right CC bits. |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ mov(ecx, Operand(eax)); |
__ and_(ecx, kSmiTagMask); |
__ xor_(ecx, kSmiTagMask); |
@@ -2878,7 +2926,7 @@ |
// Call the shared stub to get to the arguments.length. |
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
__ CallStub(&stub); |
- __ push(eax); |
+ frame_->Push(eax); |
} |
@@ -2886,7 +2934,7 @@ |
ASSERT(args->length() == 1); |
Label leave; |
Load(args->at(0)); // Load the object. |
- __ mov(eax, TOS); |
+ __ mov(eax, frame_->Top()); |
// if (object->IsSmi()) return object. |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(zero, &leave, taken); |
@@ -2897,7 +2945,7 @@ |
__ cmp(ecx, JS_VALUE_TYPE); |
__ j(not_equal, &leave, not_taken); |
__ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
- __ mov(TOS, eax); |
+ __ mov(frame_->Top(), eax); |
__ bind(&leave); |
} |
@@ -2907,8 +2955,8 @@ |
Label leave; |
Load(args->at(0)); // Load the object. |
Load(args->at(1)); // Load the value. |
- __ mov(eax, (Operand(esp, kPointerSize))); |
- __ mov(ecx, TOS); |
+ __ mov(eax, frame_->Element(1)); |
+ __ mov(ecx, frame_->Top()); |
// if (object->IsSmi()) return object. |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(zero, &leave, taken); |
@@ -2924,9 +2972,9 @@ |
__ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); |
// Leave. |
__ bind(&leave); |
- __ mov(ecx, TOS); |
- __ pop(eax); |
- __ mov(TOS, ecx); |
+ __ mov(ecx, frame_->Top()); |
+ frame_->Pop(eax); |
+ __ mov(frame_->Top(), ecx); |
} |
@@ -2941,7 +2989,7 @@ |
// Call the shared stub to get to arguments[key]. |
ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
__ CallStub(&stub); |
- __ mov(TOS, eax); |
+ __ mov(frame_->Top(), eax); |
} |
@@ -2951,8 +2999,8 @@ |
// Load the two objects into registers and perform the comparison. |
Load(args->at(0)); |
Load(args->at(1)); |
- __ pop(eax); |
- __ pop(ecx); |
+ frame_->Pop(eax); |
+ frame_->Pop(ecx); |
__ cmp(eax, Operand(ecx)); |
cc_reg_ = equal; |
} |
@@ -2967,10 +3015,10 @@ |
if (function == NULL) { |
// Prepare stack for calling JS runtime function. |
- __ push(Immediate(node->name())); |
+ frame_->Push(Immediate(node->name())); |
// Push the builtins object found in the current global object. |
__ mov(edx, GlobalObject()); |
- __ push(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); |
+ frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); |
} |
// Push the arguments ("left-to-right"). |
@@ -2980,14 +3028,14 @@ |
if (function != NULL) { |
// Call the C runtime function. |
__ CallRuntime(function, args->length()); |
- __ push(eax); |
+ frame_->Push(eax); |
} else { |
// Call the JS runtime function. |
Handle<Code> stub = ComputeCallInitialize(args->length()); |
__ Set(eax, Immediate(args->length())); |
__ call(stub, RelocInfo::CODE_TARGET); |
- __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
- __ mov(TOS, eax); |
+ __ mov(esi, frame_->Context()); |
+ __ mov(frame_->Top(), eax); |
} |
} |
@@ -3008,7 +3056,7 @@ |
Load(property->obj()); |
Load(property->key()); |
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
- __ push(eax); |
+ frame_->Push(eax); |
return; |
} |
@@ -3017,32 +3065,32 @@ |
Slot* slot = variable->slot(); |
if (variable->is_global()) { |
LoadGlobal(); |
- __ push(Immediate(variable->name())); |
+ frame_->Push(Immediate(variable->name())); |
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
- __ push(eax); |
+ frame_->Push(eax); |
return; |
} else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
// lookup the context holding the named variable |
- __ push(Operand(esi)); |
- __ push(Immediate(variable->name())); |
+ frame_->Push(esi); |
+ frame_->Push(Immediate(variable->name())); |
__ CallRuntime(Runtime::kLookupContext, 2); |
// eax: context |
- __ push(eax); |
- __ push(Immediate(variable->name())); |
+ frame_->Push(eax); |
+ frame_->Push(Immediate(variable->name())); |
__ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
- __ push(eax); |
+ frame_->Push(eax); |
return; |
} |
// Default: Result of deleting non-global, not dynamically |
// introduced variables is false. |
- __ push(Immediate(Factory::false_value())); |
+ frame_->Push(Immediate(Factory::false_value())); |
} else { |
// Default: Result of deleting expressions is true. |
Load(node->expression()); // may have side-effects |
- __ Set(TOS, Immediate(Factory::true_value())); |
+ __ Set(frame_->Top(), Immediate(Factory::true_value())); |
} |
} else if (op == Token::TYPEOF) { |
@@ -3050,7 +3098,7 @@ |
// LoadTypeofExpression(). |
LoadTypeofExpression(node->expression()); |
__ CallRuntime(Runtime::kTypeof, 1); |
- __ push(eax); |
+ frame_->Push(eax); |
} else { |
Load(node->expression()); |
@@ -3064,9 +3112,9 @@ |
case Token::SUB: { |
UnarySubStub stub; |
// TODO(1222589): remove dependency of TOS being cached inside stub |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ CallStub(&stub); |
- __ push(eax); |
+ frame_->Push(eax); |
break; |
} |
@@ -3074,11 +3122,11 @@ |
// Smi check. |
Label smi_label; |
Label continue_label; |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(zero, &smi_label, taken); |
- __ push(eax); // undo popping of TOS |
+ frame_->Push(eax); // undo popping of TOS |
__ InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION); |
__ jmp(&continue_label); |
@@ -3086,26 +3134,26 @@ |
__ not_(eax); |
__ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. |
__ bind(&continue_label); |
- __ push(eax); |
+ frame_->Push(eax); |
break; |
} |
case Token::VOID: |
- __ mov(TOS, Factory::undefined_value()); |
+ __ mov(frame_->Top(), Factory::undefined_value()); |
break; |
case Token::ADD: { |
// Smi check. |
Label continue_label; |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ test(eax, Immediate(kSmiTagMask)); |
__ j(zero, &continue_label); |
- __ push(eax); |
+ frame_->Push(eax); |
__ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); |
__ bind(&continue_label); |
- __ push(eax); |
+ frame_->Push(eax); |
break; |
} |
@@ -3211,21 +3259,24 @@ |
bool is_const = (var != NULL && var->mode() == Variable::CONST); |
// Postfix: Make room for the result. |
- if (is_postfix) __ push(Immediate(0)); |
+ if (is_postfix) { |
+ frame_->Push(Immediate(0)); |
+ } |
{ Reference target(this, node->expression()); |
if (target.is_illegal()) return; |
target.GetValue(NOT_INSIDE_TYPEOF); |
- int result_offset = target.size() * kPointerSize; |
CountOperationDeferred* deferred = |
- new CountOperationDeferred(this, is_postfix, |
- is_increment, result_offset); |
+ new CountOperationDeferred(this, is_postfix, is_increment, |
+ target.size() * kPointerSize); |
- __ pop(eax); // Load TOS into eax for calculations below |
+ frame_->Pop(eax); // Load TOS into eax for calculations below |
// Postfix: Store the old value as the result. |
- if (is_postfix) __ mov(Operand(esp, result_offset), eax); |
+ if (is_postfix) { |
+ __ mov(frame_->Element(target.size()), eax); |
+ } |
// Perform optimistic increment/decrement. |
if (is_increment) { |
@@ -3243,12 +3294,14 @@ |
// Store the new value in the target if not const. |
__ bind(deferred->exit()); |
- __ push(eax); // Push the new value to TOS |
+ frame_->Push(eax); // Push the new value to TOS |
if (!is_const) target.SetValue(NOT_CONST_INIT); |
} |
// Postfix: Discard the new value and use the old. |
- if (is_postfix) __ pop(eax); |
+ if (is_postfix) { |
+ frame_->Pop(eax); |
+ } |
} |
@@ -3287,14 +3340,14 @@ |
// standard ToBoolean() conversion as described in ECMA-262, |
// section 9.2, page 30. |
// Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
- __ mov(eax, TOS); |
- __ push(eax); |
+ __ mov(eax, frame_->Top()); |
+ frame_->Push(eax); |
ToBoolean(&pop_and_continue, &exit); |
Branch(false, &exit); |
// Pop the result of evaluating the first part. |
__ bind(&pop_and_continue); |
- __ pop(eax); |
+ frame_->Pop(eax); |
// Evaluate right side expression. |
__ bind(&is_true); |
@@ -3323,14 +3376,14 @@ |
// standard ToBoolean() conversion as described in ECMA-262, |
// section 9.2, page 30. |
// Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
- __ mov(eax, TOS); |
- __ push(eax); |
+ __ mov(eax, frame_->Top()); |
+ frame_->Push(eax); |
ToBoolean(&exit, &pop_and_continue); |
Branch(true, &exit); |
// Pop the result of evaluating the first part. |
__ bind(&pop_and_continue); |
- __ pop(eax); |
+ frame_->Pop(eax); |
// Evaluate right side expression. |
__ bind(&is_false); |
@@ -3375,7 +3428,7 @@ |
void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
- __ push(FunctionOperand()); |
+ frame_->Push(frame_->Function()); |
} |
@@ -3414,7 +3467,7 @@ |
if (left_is_null || right_is_null) { |
Load(left_is_null ? right : left); |
Label exit, undetectable; |
- __ pop(eax); |
+ frame_->Pop(eax); |
__ cmp(eax, Factory::null_value()); |
// The 'null' value is only equal to 'undefined' if using |
@@ -3458,7 +3511,7 @@ |
// Load the operand, move it to register edx, and restore TOS. |
LoadTypeofExpression(operation->expression()); |
- __ pop(edx); |
+ frame_->Pop(edx); |
if (check->Equals(Heap::number_symbol())) { |
__ test(edx, Immediate(kSmiTagMask)); |
@@ -3565,7 +3618,7 @@ |
Load(left); |
Load(right); |
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
- __ push(eax); // push the result |
+ frame_->Push(eax); // push the result |
return; |
} |
case Token::INSTANCEOF: { |
@@ -3610,7 +3663,8 @@ |
} |
-void CodeGenerator::EnterJSFrame() { |
+void VirtualFrame::Enter() { |
+ Comment cmnt(masm_, "[ Enter JS frame"); |
__ push(ebp); |
__ mov(ebp, Operand(esp)); |
@@ -3625,7 +3679,8 @@ |
} |
-void CodeGenerator::ExitJSFrame() { |
+void VirtualFrame::Exit() { |
+ Comment cmnt(masm_, "[ Exit JS frame"); |
// Record the location of the JS exit code for patching when setting |
// break point. |
__ RecordJSReturn(); |
@@ -3665,6 +3720,7 @@ |
ASSERT(!is_illegal()); |
ASSERT(!cgen_->has_cc()); |
MacroAssembler* masm = cgen_->masm(); |
+ VirtualFrame* frame = cgen_->frame(); |
switch (type_) { |
case SLOT: { |
Comment cmnt(masm, "[ Load from Slot"); |
@@ -3693,7 +3749,7 @@ |
} else { |
__ call(ic, RelocInfo::CODE_TARGET); |
} |
- __ push(eax); // IC call leaves result in eax, push it out |
+ frame->Push(eax); // IC call leaves result in eax, push it out |
break; |
} |
@@ -3713,7 +3769,7 @@ |
} else { |
__ call(ic, RelocInfo::CODE_TARGET); |
} |
- __ push(eax); // IC call leaves result in eax, push it out |
+ frame->Push(eax); // IC call leaves result in eax, push it out |
break; |
} |
@@ -3727,6 +3783,7 @@ |
ASSERT(!is_illegal()); |
ASSERT(!cgen_->has_cc()); |
MacroAssembler* masm = cgen_->masm(); |
+ VirtualFrame* frame = cgen_->frame(); |
switch (type_) { |
case SLOT: { |
Comment cmnt(masm, "[ Store to Slot"); |
@@ -3736,8 +3793,8 @@ |
ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
// For now, just do a runtime call. |
- __ push(esi); |
- __ push(Immediate(slot->var()->name())); |
+ frame->Push(esi); |
+ frame->Push(Immediate(slot->var()->name())); |
if (init_state == CONST_INIT) { |
// Same as the case for a normal store, but ignores attribute |
@@ -3762,7 +3819,7 @@ |
// Storing a variable must keep the (new) value on the expression |
// stack. This is necessary for compiling chained assignment |
// expressions. |
- __ push(eax); |
+ frame->Push(eax); |
} else { |
ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
@@ -3789,7 +3846,7 @@ |
// calling this code. |
__ pop(eax); |
__ mov(cgen_->SlotOperand(slot, ecx), eax); |
- __ push(eax); // RecordWrite may destroy the value in eax. |
+ frame->Push(eax); // RecordWrite may destroy the value in eax. |
if (slot->type() == Slot::CONTEXT) { |
// ecx is loaded with context when calling SlotOperand above. |
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
@@ -3813,7 +3870,7 @@ |
// Setup the name register. |
__ mov(ecx, name); |
__ call(ic, RelocInfo::CODE_TARGET); |
- __ push(eax); // IC call leaves result in eax, push it out |
+ frame->Push(eax); // IC call leaves result in eax, push it out |
break; |
} |
@@ -3827,7 +3884,7 @@ |
// TODO(1222589): Make the IC grab the values from the stack. |
__ pop(eax); |
__ call(ic, RelocInfo::CODE_TARGET); |
- __ push(eax); // IC call leaves result in eax, push it out |
+ frame->Push(eax); // IC call leaves result in eax, push it out |
break; |
} |