| Index: src/arm/virtual-frame-arm.cc
|
| diff --git a/src/arm/virtual-frame-arm.cc b/src/arm/virtual-frame-arm.cc
|
| deleted file mode 100644
|
| index a852d6eedf0e093fd2015fac533c570e4840d191..0000000000000000000000000000000000000000
|
| --- a/src/arm/virtual-frame-arm.cc
|
| +++ /dev/null
|
| @@ -1,843 +0,0 @@
|
| -// Copyright 2009 the V8 project authors. All rights reserved.
|
| -// Redistribution and use in source and binary forms, with or without
|
| -// modification, are permitted provided that the following conditions are
|
| -// met:
|
| -//
|
| -// * Redistributions of source code must retain the above copyright
|
| -// notice, this list of conditions and the following disclaimer.
|
| -// * Redistributions in binary form must reproduce the above
|
| -// copyright notice, this list of conditions and the following
|
| -// disclaimer in the documentation and/or other materials provided
|
| -// with the distribution.
|
| -// * Neither the name of Google Inc. nor the names of its
|
| -// contributors may be used to endorse or promote products derived
|
| -// from this software without specific prior written permission.
|
| -//
|
| -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| -
|
| -#include "v8.h"
|
| -
|
| -#if defined(V8_TARGET_ARCH_ARM)
|
| -
|
| -#include "codegen-inl.h"
|
| -#include "register-allocator-inl.h"
|
| -#include "scopes.h"
|
| -#include "virtual-frame-inl.h"
|
| -
|
| -namespace v8 {
|
| -namespace internal {
|
| -
|
| -#define __ ACCESS_MASM(masm())
|
| -
|
| -void VirtualFrame::PopToR1R0() {
|
| - // Shuffle things around so the top of stack is in r0 and r1.
|
| - MergeTOSTo(R0_R1_TOS);
|
| - // Pop the two registers off the stack so they are detached from the frame.
|
| - LowerHeight(2);
|
| - top_of_stack_state_ = NO_TOS_REGISTERS;
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::PopToR1() {
|
| - // Shuffle things around so the top of stack is only in r1.
|
| - MergeTOSTo(R1_TOS);
|
| - // Pop the register off the stack so it is detached from the frame.
|
| - LowerHeight(1);
|
| - top_of_stack_state_ = NO_TOS_REGISTERS;
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::PopToR0() {
|
| - // Shuffle things around so the top of stack only in r0.
|
| - MergeTOSTo(R0_TOS);
|
| - // Pop the register off the stack so it is detached from the frame.
|
| - LowerHeight(1);
|
| - top_of_stack_state_ = NO_TOS_REGISTERS;
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::MergeTo(const VirtualFrame* expected, Condition cond) {
|
| - if (Equals(expected)) return;
|
| - ASSERT((expected->tos_known_smi_map_ & tos_known_smi_map_) ==
|
| - expected->tos_known_smi_map_);
|
| - ASSERT(expected->IsCompatibleWith(this));
|
| - MergeTOSTo(expected->top_of_stack_state_, cond);
|
| - ASSERT(register_allocation_map_ == expected->register_allocation_map_);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::MergeTo(VirtualFrame* expected, Condition cond) {
|
| - if (Equals(expected)) return;
|
| - tos_known_smi_map_ &= expected->tos_known_smi_map_;
|
| - MergeTOSTo(expected->top_of_stack_state_, cond);
|
| - ASSERT(register_allocation_map_ == expected->register_allocation_map_);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::MergeTOSTo(
|
| - VirtualFrame::TopOfStack expected_top_of_stack_state, Condition cond) {
|
| -#define CASE_NUMBER(a, b) ((a) * TOS_STATES + (b))
|
| - switch (CASE_NUMBER(top_of_stack_state_, expected_top_of_stack_state)) {
|
| - case CASE_NUMBER(NO_TOS_REGISTERS, NO_TOS_REGISTERS):
|
| - break;
|
| - case CASE_NUMBER(NO_TOS_REGISTERS, R0_TOS):
|
| - __ pop(r0, cond);
|
| - break;
|
| - case CASE_NUMBER(NO_TOS_REGISTERS, R1_TOS):
|
| - __ pop(r1, cond);
|
| - break;
|
| - case CASE_NUMBER(NO_TOS_REGISTERS, R0_R1_TOS):
|
| - __ pop(r0, cond);
|
| - __ pop(r1, cond);
|
| - break;
|
| - case CASE_NUMBER(NO_TOS_REGISTERS, R1_R0_TOS):
|
| - __ pop(r1, cond);
|
| - __ pop(r0, cond);
|
| - break;
|
| - case CASE_NUMBER(R0_TOS, NO_TOS_REGISTERS):
|
| - __ push(r0, cond);
|
| - break;
|
| - case CASE_NUMBER(R0_TOS, R0_TOS):
|
| - break;
|
| - case CASE_NUMBER(R0_TOS, R1_TOS):
|
| - __ mov(r1, r0, LeaveCC, cond);
|
| - break;
|
| - case CASE_NUMBER(R0_TOS, R0_R1_TOS):
|
| - __ pop(r1, cond);
|
| - break;
|
| - case CASE_NUMBER(R0_TOS, R1_R0_TOS):
|
| - __ mov(r1, r0, LeaveCC, cond);
|
| - __ pop(r0, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_TOS, NO_TOS_REGISTERS):
|
| - __ push(r1, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_TOS, R0_TOS):
|
| - __ mov(r0, r1, LeaveCC, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_TOS, R1_TOS):
|
| - break;
|
| - case CASE_NUMBER(R1_TOS, R0_R1_TOS):
|
| - __ mov(r0, r1, LeaveCC, cond);
|
| - __ pop(r1, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_TOS, R1_R0_TOS):
|
| - __ pop(r0, cond);
|
| - break;
|
| - case CASE_NUMBER(R0_R1_TOS, NO_TOS_REGISTERS):
|
| - __ Push(r1, r0, cond);
|
| - break;
|
| - case CASE_NUMBER(R0_R1_TOS, R0_TOS):
|
| - __ push(r1, cond);
|
| - break;
|
| - case CASE_NUMBER(R0_R1_TOS, R1_TOS):
|
| - __ push(r1, cond);
|
| - __ mov(r1, r0, LeaveCC, cond);
|
| - break;
|
| - case CASE_NUMBER(R0_R1_TOS, R0_R1_TOS):
|
| - break;
|
| - case CASE_NUMBER(R0_R1_TOS, R1_R0_TOS):
|
| - __ Swap(r0, r1, ip, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_R0_TOS, NO_TOS_REGISTERS):
|
| - __ Push(r0, r1, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_R0_TOS, R0_TOS):
|
| - __ push(r0, cond);
|
| - __ mov(r0, r1, LeaveCC, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_R0_TOS, R1_TOS):
|
| - __ push(r0, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_R0_TOS, R0_R1_TOS):
|
| - __ Swap(r0, r1, ip, cond);
|
| - break;
|
| - case CASE_NUMBER(R1_R0_TOS, R1_R0_TOS):
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| -#undef CASE_NUMBER
|
| - }
|
| - // A conditional merge will be followed by a conditional branch and the
|
| - // fall-through code will have an unchanged virtual frame state. If the
|
| - // merge is unconditional ('al'ways) then it might be followed by a fall
|
| - // through. We need to update the virtual frame state to match the code we
|
| - // are falling into. The final case is an unconditional merge followed by an
|
| - // unconditional branch, in which case it doesn't matter what we do to the
|
| - // virtual frame state, because the virtual frame will be invalidated.
|
| - if (cond == al) {
|
| - top_of_stack_state_ = expected_top_of_stack_state;
|
| - }
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::Enter() {
|
| - Comment cmnt(masm(), "[ Enter JS frame");
|
| -
|
| -#ifdef DEBUG
|
| - // Verify that r1 contains a JS function. The following code relies
|
| - // on r2 being available for use.
|
| - if (FLAG_debug_code) {
|
| - Label map_check, done;
|
| - __ tst(r1, Operand(kSmiTagMask));
|
| - __ b(ne, &map_check);
|
| - __ stop("VirtualFrame::Enter - r1 is not a function (smi check).");
|
| - __ bind(&map_check);
|
| - __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
|
| - __ b(eq, &done);
|
| - __ stop("VirtualFrame::Enter - r1 is not a function (map check).");
|
| - __ bind(&done);
|
| - }
|
| -#endif // DEBUG
|
| -
|
| - // We are about to push four values to the frame.
|
| - Adjust(4);
|
| - __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
|
| - // Adjust FP to point to saved FP.
|
| - __ add(fp, sp, Operand(2 * kPointerSize));
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::Exit() {
|
| - Comment cmnt(masm(), "[ Exit JS frame");
|
| - // Record the location of the JS exit code for patching when setting
|
| - // break point.
|
| - __ RecordJSReturn();
|
| -
|
| - // Drop the execution stack down to the frame pointer and restore the caller
|
| - // frame pointer and return address.
|
| - __ mov(sp, fp);
|
| - __ ldm(ia_w, sp, fp.bit() | lr.bit());
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::AllocateStackSlots() {
|
| - int count = local_count();
|
| - if (count > 0) {
|
| - Comment cmnt(masm(), "[ Allocate space for locals");
|
| - Adjust(count);
|
| - // Initialize stack slots with 'undefined' value.
|
| - __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| - __ LoadRoot(r2, Heap::kStackLimitRootIndex);
|
| - if (count < kLocalVarBound) {
|
| - // For less locals the unrolled loop is more compact.
|
| - for (int i = 0; i < count; i++) {
|
| - __ push(ip);
|
| - }
|
| - } else {
|
| - // For more locals a loop in generated code is more compact.
|
| - Label alloc_locals_loop;
|
| - __ mov(r1, Operand(count));
|
| - __ bind(&alloc_locals_loop);
|
| - __ push(ip);
|
| - __ sub(r1, r1, Operand(1), SetCC);
|
| - __ b(ne, &alloc_locals_loop);
|
| - }
|
| - } else {
|
| - __ LoadRoot(r2, Heap::kStackLimitRootIndex);
|
| - }
|
| - // Check the stack for overflow or a break request.
|
| - masm()->cmp(sp, Operand(r2));
|
| - StackCheckStub stub;
|
| - // Call the stub if lower.
|
| - masm()->mov(ip,
|
| - Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
|
| - RelocInfo::CODE_TARGET),
|
| - LeaveCC,
|
| - lo);
|
| - masm()->Call(ip, lo);
|
| -}
|
| -
|
| -
|
| -
|
| -void VirtualFrame::PushReceiverSlotAddress() {
|
| - UNIMPLEMENTED();
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::PushTryHandler(HandlerType type) {
|
| - // Grow the expression stack by handler size less one (the return
|
| - // address in lr is already counted by a call instruction).
|
| - Adjust(kHandlerSize - 1);
|
| - __ PushTryHandler(IN_JAVASCRIPT, type);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::CallJSFunction(int arg_count) {
|
| - // InvokeFunction requires function in r1.
|
| - PopToR1();
|
| - SpillAll();
|
| -
|
| - // +1 for receiver.
|
| - Forget(arg_count + 1);
|
| - ASSERT(cgen()->HasValidEntryRegisters());
|
| - ParameterCount count(arg_count);
|
| - __ InvokeFunction(r1, count, CALL_FUNCTION);
|
| - // Restore the context.
|
| - __ ldr(cp, Context());
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::CallRuntime(const Runtime::Function* f, int arg_count) {
|
| - SpillAll();
|
| - Forget(arg_count);
|
| - ASSERT(cgen()->HasValidEntryRegisters());
|
| - __ CallRuntime(f, arg_count);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
|
| - SpillAll();
|
| - Forget(arg_count);
|
| - ASSERT(cgen()->HasValidEntryRegisters());
|
| - __ CallRuntime(id, arg_count);
|
| -}
|
| -
|
| -
|
| -#ifdef ENABLE_DEBUGGER_SUPPORT
|
| -void VirtualFrame::DebugBreak() {
|
| - ASSERT(cgen()->HasValidEntryRegisters());
|
| - __ DebugBreak();
|
| -}
|
| -#endif
|
| -
|
| -
|
| -void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
|
| - InvokeJSFlags flags,
|
| - int arg_count) {
|
| - Forget(arg_count);
|
| - __ InvokeBuiltin(id, flags);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::CallLoadIC(Handle<String> name, RelocInfo::Mode mode) {
|
| - Handle<Code> ic(Isolate::Current()->builtins()->builtin(
|
| - Builtins::kLoadIC_Initialize));
|
| - PopToR0();
|
| - SpillAll();
|
| - __ mov(r2, Operand(name));
|
| - CallCodeObject(ic, mode, 0);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::CallStoreIC(Handle<String> name,
|
| - bool is_contextual,
|
| - StrictModeFlag strict_mode) {
|
| - Handle<Code> ic(Isolate::Current()->builtins()->builtin(
|
| - (strict_mode == kStrictMode) ? Builtins::kStoreIC_Initialize_Strict
|
| - : Builtins::kStoreIC_Initialize));
|
| - PopToR0();
|
| - RelocInfo::Mode mode;
|
| - if (is_contextual) {
|
| - SpillAll();
|
| - __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
| - mode = RelocInfo::CODE_TARGET_CONTEXT;
|
| - } else {
|
| - EmitPop(r1);
|
| - SpillAll();
|
| - mode = RelocInfo::CODE_TARGET;
|
| - }
|
| - __ mov(r2, Operand(name));
|
| - CallCodeObject(ic, mode, 0);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::CallKeyedLoadIC() {
|
| - Handle<Code> ic(Isolate::Current()->builtins()->builtin(
|
| - Builtins::kKeyedLoadIC_Initialize));
|
| - PopToR1R0();
|
| - SpillAll();
|
| - CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::CallKeyedStoreIC(StrictModeFlag strict_mode) {
|
| - Handle<Code> ic(Isolate::Current()->builtins()->builtin(
|
| - (strict_mode == kStrictMode) ? Builtins::kKeyedStoreIC_Initialize_Strict
|
| - : Builtins::kKeyedStoreIC_Initialize));
|
| - PopToR1R0();
|
| - SpillAll();
|
| - EmitPop(r2);
|
| - CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::CallCodeObject(Handle<Code> code,
|
| - RelocInfo::Mode rmode,
|
| - int dropped_args) {
|
| - switch (code->kind()) {
|
| - case Code::CALL_IC:
|
| - case Code::KEYED_CALL_IC:
|
| - case Code::FUNCTION:
|
| - break;
|
| - case Code::KEYED_LOAD_IC:
|
| - case Code::LOAD_IC:
|
| - case Code::KEYED_STORE_IC:
|
| - case Code::STORE_IC:
|
| - ASSERT(dropped_args == 0);
|
| - break;
|
| - case Code::BUILTIN:
|
| - ASSERT(*code == Isolate::Current()->builtins()->builtin(
|
| - Builtins::kJSConstructCall));
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - Forget(dropped_args);
|
| - ASSERT(cgen()->HasValidEntryRegisters());
|
| - __ Call(code, rmode);
|
| -}
|
| -
|
| -
|
| -// NO_TOS_REGISTERS, R0_TOS, R1_TOS, R1_R0_TOS, R0_R1_TOS.
|
| -const bool VirtualFrame::kR0InUse[TOS_STATES] =
|
| - { false, true, false, true, true };
|
| -const bool VirtualFrame::kR1InUse[TOS_STATES] =
|
| - { false, false, true, true, true };
|
| -const int VirtualFrame::kVirtualElements[TOS_STATES] =
|
| - { 0, 1, 1, 2, 2 };
|
| -const Register VirtualFrame::kTopRegister[TOS_STATES] =
|
| - { r0, r0, r1, r1, r0 };
|
| -const Register VirtualFrame::kBottomRegister[TOS_STATES] =
|
| - { r0, r0, r1, r0, r1 };
|
| -const Register VirtualFrame::kAllocatedRegisters[
|
| - VirtualFrame::kNumberOfAllocatedRegisters] = { r2, r3, r4, r5, r6 };
|
| -// Popping is done by the transition implied by kStateAfterPop. Of course if
|
| -// there were no stack slots allocated to registers then the physical SP must
|
| -// be adjusted.
|
| -const VirtualFrame::TopOfStack VirtualFrame::kStateAfterPop[TOS_STATES] =
|
| - { NO_TOS_REGISTERS, NO_TOS_REGISTERS, NO_TOS_REGISTERS, R0_TOS, R1_TOS };
|
| -// Pushing is done by the transition implied by kStateAfterPush. Of course if
|
| -// the maximum number of registers was already allocated to the top of stack
|
| -// slots then one register must be physically pushed onto the stack.
|
| -const VirtualFrame::TopOfStack VirtualFrame::kStateAfterPush[TOS_STATES] =
|
| - { R0_TOS, R1_R0_TOS, R0_R1_TOS, R0_R1_TOS, R1_R0_TOS };
|
| -
|
| -
|
| -void VirtualFrame::Drop(int count) {
|
| - ASSERT(count >= 0);
|
| - ASSERT(height() >= count);
|
| - // Discard elements from the virtual frame and free any registers.
|
| - int num_virtual_elements = kVirtualElements[top_of_stack_state_];
|
| - while (num_virtual_elements > 0) {
|
| - Pop();
|
| - num_virtual_elements--;
|
| - count--;
|
| - if (count == 0) return;
|
| - }
|
| - if (count == 0) return;
|
| - __ add(sp, sp, Operand(count * kPointerSize));
|
| - LowerHeight(count);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::Pop() {
|
| - if (top_of_stack_state_ == NO_TOS_REGISTERS) {
|
| - __ add(sp, sp, Operand(kPointerSize));
|
| - } else {
|
| - top_of_stack_state_ = kStateAfterPop[top_of_stack_state_];
|
| - }
|
| - LowerHeight(1);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::EmitPop(Register reg) {
|
| - ASSERT(!is_used(RegisterAllocator::ToNumber(reg)));
|
| - if (top_of_stack_state_ == NO_TOS_REGISTERS) {
|
| - __ pop(reg);
|
| - } else {
|
| - __ mov(reg, kTopRegister[top_of_stack_state_]);
|
| - top_of_stack_state_ = kStateAfterPop[top_of_stack_state_];
|
| - }
|
| - LowerHeight(1);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::SpillAllButCopyTOSToR0() {
|
| - switch (top_of_stack_state_) {
|
| - case NO_TOS_REGISTERS:
|
| - __ ldr(r0, MemOperand(sp, 0));
|
| - break;
|
| - case R0_TOS:
|
| - __ push(r0);
|
| - break;
|
| - case R1_TOS:
|
| - __ push(r1);
|
| - __ mov(r0, r1);
|
| - break;
|
| - case R0_R1_TOS:
|
| - __ Push(r1, r0);
|
| - break;
|
| - case R1_R0_TOS:
|
| - __ Push(r0, r1);
|
| - __ mov(r0, r1);
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - top_of_stack_state_ = NO_TOS_REGISTERS;
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::SpillAllButCopyTOSToR1() {
|
| - switch (top_of_stack_state_) {
|
| - case NO_TOS_REGISTERS:
|
| - __ ldr(r1, MemOperand(sp, 0));
|
| - break;
|
| - case R0_TOS:
|
| - __ push(r0);
|
| - __ mov(r1, r0);
|
| - break;
|
| - case R1_TOS:
|
| - __ push(r1);
|
| - break;
|
| - case R0_R1_TOS:
|
| - __ Push(r1, r0);
|
| - __ mov(r1, r0);
|
| - break;
|
| - case R1_R0_TOS:
|
| - __ Push(r0, r1);
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - top_of_stack_state_ = NO_TOS_REGISTERS;
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::SpillAllButCopyTOSToR1R0() {
|
| - switch (top_of_stack_state_) {
|
| - case NO_TOS_REGISTERS:
|
| - __ ldr(r1, MemOperand(sp, 0));
|
| - __ ldr(r0, MemOperand(sp, kPointerSize));
|
| - break;
|
| - case R0_TOS:
|
| - __ push(r0);
|
| - __ mov(r1, r0);
|
| - __ ldr(r0, MemOperand(sp, kPointerSize));
|
| - break;
|
| - case R1_TOS:
|
| - __ push(r1);
|
| - __ ldr(r0, MemOperand(sp, kPointerSize));
|
| - break;
|
| - case R0_R1_TOS:
|
| - __ Push(r1, r0);
|
| - __ Swap(r0, r1, ip);
|
| - break;
|
| - case R1_R0_TOS:
|
| - __ Push(r0, r1);
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - top_of_stack_state_ = NO_TOS_REGISTERS;
|
| -}
|
| -
|
| -
|
| -Register VirtualFrame::Peek() {
|
| - AssertIsNotSpilled();
|
| - if (top_of_stack_state_ == NO_TOS_REGISTERS) {
|
| - top_of_stack_state_ = kStateAfterPush[top_of_stack_state_];
|
| - Register answer = kTopRegister[top_of_stack_state_];
|
| - __ pop(answer);
|
| - return answer;
|
| - } else {
|
| - return kTopRegister[top_of_stack_state_];
|
| - }
|
| -}
|
| -
|
| -
|
| -Register VirtualFrame::Peek2() {
|
| - AssertIsNotSpilled();
|
| - switch (top_of_stack_state_) {
|
| - case NO_TOS_REGISTERS:
|
| - case R0_TOS:
|
| - case R0_R1_TOS:
|
| - MergeTOSTo(R0_R1_TOS);
|
| - return r1;
|
| - case R1_TOS:
|
| - case R1_R0_TOS:
|
| - MergeTOSTo(R1_R0_TOS);
|
| - return r0;
|
| - default:
|
| - UNREACHABLE();
|
| - return no_reg;
|
| - }
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::Dup() {
|
| - if (SpilledScope::is_spilled()) {
|
| - __ ldr(ip, MemOperand(sp, 0));
|
| - __ push(ip);
|
| - } else {
|
| - switch (top_of_stack_state_) {
|
| - case NO_TOS_REGISTERS:
|
| - __ ldr(r0, MemOperand(sp, 0));
|
| - top_of_stack_state_ = R0_TOS;
|
| - break;
|
| - case R0_TOS:
|
| - __ mov(r1, r0);
|
| - // r0 and r1 contains the same value. Prefer state with r0 holding TOS.
|
| - top_of_stack_state_ = R0_R1_TOS;
|
| - break;
|
| - case R1_TOS:
|
| - __ mov(r0, r1);
|
| - // r0 and r1 contains the same value. Prefer state with r0 holding TOS.
|
| - top_of_stack_state_ = R0_R1_TOS;
|
| - break;
|
| - case R0_R1_TOS:
|
| - __ push(r1);
|
| - __ mov(r1, r0);
|
| - // r0 and r1 contains the same value. Prefer state with r0 holding TOS.
|
| - top_of_stack_state_ = R0_R1_TOS;
|
| - break;
|
| - case R1_R0_TOS:
|
| - __ push(r0);
|
| - __ mov(r0, r1);
|
| - // r0 and r1 contains the same value. Prefer state with r0 holding TOS.
|
| - top_of_stack_state_ = R0_R1_TOS;
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - }
|
| - RaiseHeight(1, tos_known_smi_map_ & 1);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::Dup2() {
|
| - if (SpilledScope::is_spilled()) {
|
| - __ ldr(ip, MemOperand(sp, kPointerSize));
|
| - __ push(ip);
|
| - __ ldr(ip, MemOperand(sp, kPointerSize));
|
| - __ push(ip);
|
| - } else {
|
| - switch (top_of_stack_state_) {
|
| - case NO_TOS_REGISTERS:
|
| - __ ldr(r0, MemOperand(sp, 0));
|
| - __ ldr(r1, MemOperand(sp, kPointerSize));
|
| - top_of_stack_state_ = R0_R1_TOS;
|
| - break;
|
| - case R0_TOS:
|
| - __ push(r0);
|
| - __ ldr(r1, MemOperand(sp, kPointerSize));
|
| - top_of_stack_state_ = R0_R1_TOS;
|
| - break;
|
| - case R1_TOS:
|
| - __ push(r1);
|
| - __ ldr(r0, MemOperand(sp, kPointerSize));
|
| - top_of_stack_state_ = R1_R0_TOS;
|
| - break;
|
| - case R0_R1_TOS:
|
| - __ Push(r1, r0);
|
| - top_of_stack_state_ = R0_R1_TOS;
|
| - break;
|
| - case R1_R0_TOS:
|
| - __ Push(r0, r1);
|
| - top_of_stack_state_ = R1_R0_TOS;
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - }
|
| - RaiseHeight(2, tos_known_smi_map_ & 3);
|
| -}
|
| -
|
| -
|
| -Register VirtualFrame::PopToRegister(Register but_not_to_this_one) {
|
| - ASSERT(but_not_to_this_one.is(r0) ||
|
| - but_not_to_this_one.is(r1) ||
|
| - but_not_to_this_one.is(no_reg));
|
| - LowerHeight(1);
|
| - if (top_of_stack_state_ == NO_TOS_REGISTERS) {
|
| - if (but_not_to_this_one.is(r0)) {
|
| - __ pop(r1);
|
| - return r1;
|
| - } else {
|
| - __ pop(r0);
|
| - return r0;
|
| - }
|
| - } else {
|
| - Register answer = kTopRegister[top_of_stack_state_];
|
| - ASSERT(!answer.is(but_not_to_this_one));
|
| - top_of_stack_state_ = kStateAfterPop[top_of_stack_state_];
|
| - return answer;
|
| - }
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::EnsureOneFreeTOSRegister() {
|
| - if (kVirtualElements[top_of_stack_state_] == kMaxTOSRegisters) {
|
| - __ push(kBottomRegister[top_of_stack_state_]);
|
| - top_of_stack_state_ = kStateAfterPush[top_of_stack_state_];
|
| - top_of_stack_state_ = kStateAfterPop[top_of_stack_state_];
|
| - }
|
| - ASSERT(kVirtualElements[top_of_stack_state_] != kMaxTOSRegisters);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::EmitPush(Register reg, TypeInfo info) {
|
| - RaiseHeight(1, info.IsSmi() ? 1 : 0);
|
| - if (reg.is(cp)) {
|
| - // If we are pushing cp then we are about to make a call and things have to
|
| - // be pushed to the physical stack. There's nothing to be gained my moving
|
| - // to a TOS register and then pushing that, we might as well push to the
|
| - // physical stack immediately.
|
| - MergeTOSTo(NO_TOS_REGISTERS);
|
| - __ push(reg);
|
| - return;
|
| - }
|
| - if (SpilledScope::is_spilled()) {
|
| - ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
|
| - __ push(reg);
|
| - return;
|
| - }
|
| - if (top_of_stack_state_ == NO_TOS_REGISTERS) {
|
| - if (reg.is(r0)) {
|
| - top_of_stack_state_ = R0_TOS;
|
| - return;
|
| - }
|
| - if (reg.is(r1)) {
|
| - top_of_stack_state_ = R1_TOS;
|
| - return;
|
| - }
|
| - }
|
| - EnsureOneFreeTOSRegister();
|
| - top_of_stack_state_ = kStateAfterPush[top_of_stack_state_];
|
| - Register dest = kTopRegister[top_of_stack_state_];
|
| - __ Move(dest, reg);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::SetElementAt(Register reg, int this_far_down) {
|
| - if (this_far_down < kTOSKnownSmiMapSize) {
|
| - tos_known_smi_map_ &= ~(1 << this_far_down);
|
| - }
|
| - if (this_far_down == 0) {
|
| - Pop();
|
| - Register dest = GetTOSRegister();
|
| - if (dest.is(reg)) {
|
| - // We already popped one item off the top of the stack. If the only
|
| - // free register is the one we were asked to push then we have been
|
| - // asked to push a register that was already in use, which cannot
|
| - // happen. It therefore folows that there are two free TOS registers:
|
| - ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
|
| - dest = dest.is(r0) ? r1 : r0;
|
| - }
|
| - __ mov(dest, reg);
|
| - EmitPush(dest);
|
| - } else if (this_far_down == 1) {
|
| - int virtual_elements = kVirtualElements[top_of_stack_state_];
|
| - if (virtual_elements < 2) {
|
| - __ str(reg, ElementAt(this_far_down));
|
| - } else {
|
| - ASSERT(virtual_elements == 2);
|
| - ASSERT(!reg.is(r0));
|
| - ASSERT(!reg.is(r1));
|
| - Register dest = kBottomRegister[top_of_stack_state_];
|
| - __ mov(dest, reg);
|
| - }
|
| - } else {
|
| - ASSERT(this_far_down >= 2);
|
| - ASSERT(kVirtualElements[top_of_stack_state_] <= 2);
|
| - __ str(reg, ElementAt(this_far_down));
|
| - }
|
| -}
|
| -
|
| -
|
| -Register VirtualFrame::GetTOSRegister() {
|
| - if (SpilledScope::is_spilled()) return r0;
|
| -
|
| - EnsureOneFreeTOSRegister();
|
| - return kTopRegister[kStateAfterPush[top_of_stack_state_]];
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::EmitPush(Operand operand, TypeInfo info) {
|
| - RaiseHeight(1, info.IsSmi() ? 1 : 0);
|
| - if (SpilledScope::is_spilled()) {
|
| - __ mov(r0, operand);
|
| - __ push(r0);
|
| - return;
|
| - }
|
| - EnsureOneFreeTOSRegister();
|
| - top_of_stack_state_ = kStateAfterPush[top_of_stack_state_];
|
| - __ mov(kTopRegister[top_of_stack_state_], operand);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::EmitPush(MemOperand operand, TypeInfo info) {
|
| - RaiseHeight(1, info.IsSmi() ? 1 : 0);
|
| - if (SpilledScope::is_spilled()) {
|
| - __ ldr(r0, operand);
|
| - __ push(r0);
|
| - return;
|
| - }
|
| - EnsureOneFreeTOSRegister();
|
| - top_of_stack_state_ = kStateAfterPush[top_of_stack_state_];
|
| - __ ldr(kTopRegister[top_of_stack_state_], operand);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::EmitPushRoot(Heap::RootListIndex index) {
|
| - RaiseHeight(1, 0);
|
| - if (SpilledScope::is_spilled()) {
|
| - __ LoadRoot(r0, index);
|
| - __ push(r0);
|
| - return;
|
| - }
|
| - EnsureOneFreeTOSRegister();
|
| - top_of_stack_state_ = kStateAfterPush[top_of_stack_state_];
|
| - __ LoadRoot(kTopRegister[top_of_stack_state_], index);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::EmitPushMultiple(int count, int src_regs) {
|
| - ASSERT(SpilledScope::is_spilled());
|
| - Adjust(count);
|
| - __ stm(db_w, sp, src_regs);
|
| -}
|
| -
|
| -
|
| -void VirtualFrame::SpillAll() {
|
| - switch (top_of_stack_state_) {
|
| - case R1_R0_TOS:
|
| - masm()->push(r0);
|
| - // Fall through.
|
| - case R1_TOS:
|
| - masm()->push(r1);
|
| - top_of_stack_state_ = NO_TOS_REGISTERS;
|
| - break;
|
| - case R0_R1_TOS:
|
| - masm()->push(r1);
|
| - // Fall through.
|
| - case R0_TOS:
|
| - masm()->push(r0);
|
| - top_of_stack_state_ = NO_TOS_REGISTERS;
|
| - // Fall through.
|
| - case NO_TOS_REGISTERS:
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - ASSERT(register_allocation_map_ == 0); // Not yet implemented.
|
| -}
|
| -
|
| -#undef __
|
| -
|
| -} } // namespace v8::internal
|
| -
|
| -#endif // V8_TARGET_ARCH_ARM
|
|
|