Chromium Code Reviews| 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; |
| } |