/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=4 sw=4 et tw=99: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released * May 28, 2008. * * The Initial Developer of the Original Code is * Brendan Eich * * Contributor(s): * David Anderson * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #if !defined jsjaeger_regstate_h__ && defined JS_METHODJIT #define jsjaeger_regstate_h__ #include "jsbit.h" #include "assembler/assembler/MacroAssembler.h" namespace js { namespace mjit { struct Registers { enum CallConvention { NormalCall, FastCall }; typedef JSC::MacroAssembler::RegisterID RegisterID; // Homed and scratch registers for working with Values on x64. #if defined(JS_CPU_X64) static const RegisterID TypeMaskReg = JSC::X86Registers::r13; static const RegisterID PayloadMaskReg = JSC::X86Registers::r14; static const RegisterID ValueReg = JSC::X86Registers::r10; #endif // Register that homes the current JSStackFrame. #if defined(JS_CPU_X86) || defined(JS_CPU_X64) static const RegisterID JSFrameReg = JSC::X86Registers::ebx; #elif defined(JS_CPU_ARM) static const RegisterID JSFrameReg = JSC::ARMRegisters::r11; #endif #if defined(JS_CPU_X86) || defined(JS_CPU_X64) static const RegisterID ReturnReg = JSC::X86Registers::eax; # if defined(JS_CPU_X86) || defined(_MSC_VER) static const RegisterID ArgReg0 = JSC::X86Registers::ecx; static const RegisterID ArgReg1 = JSC::X86Registers::edx; # if defined(JS_CPU_X64) static const RegisterID ArgReg2 = JSC::X86Registers::r8; # endif # else static const RegisterID ArgReg0 = JSC::X86Registers::edi; static const RegisterID ArgReg1 = JSC::X86Registers::esi; static const RegisterID ArgReg2 = JSC::X86Registers::edx; # endif #elif JS_CPU_ARM static const RegisterID ReturnReg = JSC::ARMRegisters::r0; static const RegisterID ArgReg0 = JSC::ARMRegisters::r0; static const RegisterID ArgReg1 = JSC::ARMRegisters::r1; static const RegisterID ArgReg2 = JSC::ARMRegisters::r2; #endif static const RegisterID StackPointer = JSC::MacroAssembler::stackPointerRegister; static inline uint32 maskReg(RegisterID reg) { return (1 << reg); } static inline uint32 mask2Regs(RegisterID reg1, RegisterID reg2) { return maskReg(reg1) | maskReg(reg2); } static inline uint32 mask3Regs(RegisterID reg1, RegisterID reg2, RegisterID reg3) { return maskReg(reg1) | maskReg(reg2) | maskReg(reg3); } #if defined(JS_CPU_X86) || defined(JS_CPU_X64) static const uint32 TempRegs = (1 << JSC::X86Registers::eax) | (1 << JSC::X86Registers::ecx) | (1 << JSC::X86Registers::edx) # if defined(JS_CPU_X64) | (1 << JSC::X86Registers::r8) | (1 << JSC::X86Registers::r9) # if !defined(_MSC_VER) | (1 << JSC::X86Registers::esi) | (1 << JSC::X86Registers::edi) # endif # endif ; # if defined(JS_CPU_X64) static const uint32 SavedRegs = /* r11 is scratchRegister, used by JSC. */ (1 << JSC::X86Registers::r12) // r13 is TypeMaskReg. // r14 is PayloadMaskReg. | (1 << JSC::X86Registers::r15) # if defined(_MSC_VER) | (1 << JSC::X86Registers::esi) | (1 << JSC::X86Registers::edi) # endif # else static const uint32 SavedRegs = (1 << JSC::X86Registers::esi) | (1 << JSC::X86Registers::edi) # endif ; # if defined(JS_CPU_X86) static const uint32 SingleByteRegs = (TempRegs | SavedRegs) & ~((1 << JSC::X86Registers::esi) | (1 << JSC::X86Registers::edi) | (1 << JSC::X86Registers::ebp) | (1 << JSC::X86Registers::esp)); # elif defined(JS_CPU_X64) static const uint32 SingleByteRegs = TempRegs | SavedRegs; # endif #elif defined(JS_CPU_ARM) static const uint32 TempRegs = (1 << JSC::ARMRegisters::r0) | (1 << JSC::ARMRegisters::r1) | (1 << JSC::ARMRegisters::r2); // r3 is reserved as a scratch register for the assembler. static const uint32 SavedRegs = (1 << JSC::ARMRegisters::r4) | (1 << JSC::ARMRegisters::r5) | (1 << JSC::ARMRegisters::r6) | (1 << JSC::ARMRegisters::r7) // r8 is reserved as a scratch register for the assembler. | (1 << JSC::ARMRegisters::r9) | (1 << JSC::ARMRegisters::r10); // r11 is reserved for JSFrameReg. // r12 is IP, and is used for stub calls. // r13 is SP and must always point to VMFrame whilst in generated code. // r14 is LR and is used for return sequences. // r15 is PC (program counter). static const uint32 SingleByteRegs = TempRegs | SavedRegs; #else # error "Unsupported platform" #endif static const uint32 AvailRegs = SavedRegs | TempRegs; static bool isSaved(RegisterID reg) { uint32 mask = maskReg(reg); JS_ASSERT(mask & AvailRegs); return bool(mask & SavedRegs); } static inline uint32 numArgRegs(CallConvention convention) { #if defined(JS_CPU_X86) # if defined(JS_NO_FASTCALL) return 0; # else return (convention == FastCall) ? 2 : 0; # endif #elif defined(JS_CPU_X64) # ifdef _WIN64 return 4; # else return 6; # endif #elif defined(JS_CPU_ARM) return 4; #endif } static inline bool regForArg(CallConvention conv, uint32 i, RegisterID *reg) { #if defined(JS_CPU_X86) static const RegisterID regs[] = { JSC::X86Registers::ecx, JSC::X86Registers::edx }; # if defined(JS_NO_FASTCALL) return false; # else if (conv == NormalCall) return false; # endif #elif defined(JS_CPU_X64) # ifdef _WIN64 static const RegisterID regs[] = { JSC::X86Registers::ecx, JSC::X86Registers::edx, JSC::X86Registers::r8, JSC::X86Registers::r9 }; # else static const RegisterID regs[] = { JSC::X86Registers::edi, JSC::X86Registers::esi, JSC::X86Registers::edx, JSC::X86Registers::ecx, JSC::X86Registers::r8, JSC::X86Registers::r9 }; # endif #elif defined(JS_CPU_ARM) static const RegisterID regs[] = { JSC::ARMRegisters::r0, JSC::ARMRegisters::r1, JSC::ARMRegisters::r2, JSC::ARMRegisters::r3 }; #endif JS_ASSERT(numArgRegs(conv) == JS_ARRAY_LENGTH(regs)); if (i > JS_ARRAY_LENGTH(regs)) return false; *reg = regs[i]; return true; } Registers() : freeMask(AvailRegs) { } Registers(uint32 freeMask) : freeMask(freeMask) { } Registers(const Registers &other) : freeMask(other.freeMask) { } Registers & operator =(const Registers &other) { freeMask = other.freeMask; return *this; } void reset() { freeMask = AvailRegs; } bool empty() const { return !freeMask; } bool empty(uint32 mask) const { return !(freeMask & mask); } RegisterID peekReg() { JS_ASSERT(!empty()); int ireg; JS_FLOOR_LOG2(ireg, freeMask); RegisterID reg = (RegisterID)ireg; return reg; } RegisterID takeAnyReg() { RegisterID reg = peekReg(); takeReg(reg); return reg; } bool hasRegInMask(uint32 mask) const { Registers temp(freeMask & mask); return !temp.empty(); } RegisterID takeRegInMask(uint32 mask) { Registers temp(freeMask & mask); RegisterID reg = temp.takeAnyReg(); takeReg(reg); return reg; } bool hasReg(RegisterID reg) const { return !!(freeMask & (1 << reg)); } void putRegUnchecked(RegisterID reg) { freeMask |= (1 << reg); } void putReg(RegisterID reg) { JS_ASSERT(!hasReg(reg)); putRegUnchecked(reg); } void takeReg(RegisterID reg) { JS_ASSERT(hasReg(reg)); takeRegUnchecked(reg); } void takeRegUnchecked(RegisterID reg) { freeMask &= ~(1 << reg); } bool operator ==(const Registers &other) { return freeMask == other.freeMask; } uint32 freeMask; }; struct FPRegisters { typedef JSC::MacroAssembler::FPRegisterID FPRegisterID; #if defined(JS_CPU_X86) || defined(JS_CPU_X64) static const uint32 TotalFPRegisters = 8; static const uint32 TempFPRegs = (1 << JSC::X86Registers::xmm0) | (1 << JSC::X86Registers::xmm1) | (1 << JSC::X86Registers::xmm2) | (1 << JSC::X86Registers::xmm3) | (1 << JSC::X86Registers::xmm4) | (1 << JSC::X86Registers::xmm5) | (1 << JSC::X86Registers::xmm6) | (1 << JSC::X86Registers::xmm7); /* FIXME: Temporary hack until FPRegister allocation exists. */ static const FPRegisterID First = JSC::X86Registers::xmm0; static const FPRegisterID Second = JSC::X86Registers::xmm1; static const FPRegisterID Temp0 = JSC::X86Registers::xmm2; static const FPRegisterID Temp1 = JSC::X86Registers::xmm3; #elif defined(JS_CPU_ARM) static const uint32 TotalFPRegisters = 4; static const uint32 TempFPRegs = (1 << JSC::ARMRegisters::d0) | (1 << JSC::ARMRegisters::d1) | (1 << JSC::ARMRegisters::d2) | (1 << JSC::ARMRegisters::d3); /* FIXME: Temporary hack until FPRegister allocation exists. */ static const FPRegisterID First = JSC::ARMRegisters::d0; static const FPRegisterID Second = JSC::ARMRegisters::d1; static const FPRegisterID Temp0 = JSC::ARMRegisters::d2; static const FPRegisterID Temp1 = JSC::ARMRegisters::d3; #else # error "Unsupported platform" #endif static const uint32 AvailFPRegs = TempFPRegs; FPRegisters() : freeFPMask(AvailFPRegs) { } FPRegisters(uint32 freeFPMask) : freeFPMask(freeFPMask) { } FPRegisters(const FPRegisters &other) : freeFPMask(other.freeFPMask) { } FPRegisters & operator =(const FPRegisters &other) { freeFPMask = other.freeFPMask; return *this; } void reset() { freeFPMask = AvailFPRegs; } bool empty() const { return !freeFPMask; } bool empty(uint32 mask) const { return !(freeFPMask & mask); } FPRegisterID takeAnyReg() { JS_ASSERT(!empty()); int ireg; JS_FLOOR_LOG2(ireg, freeFPMask); FPRegisterID reg = (FPRegisterID)ireg; takeReg(reg); return reg; } bool hasRegInMask(uint32 mask) const { FPRegisters temp(freeFPMask & mask); return !temp.empty(); } FPRegisterID takeRegInMask(uint32 mask) { FPRegisters temp(freeFPMask & mask); FPRegisterID reg = temp.takeAnyReg(); takeReg(reg); return reg; } bool hasReg(FPRegisterID fpreg) const { return !!(freeFPMask & (1 << fpreg)); } void putRegUnchecked(FPRegisterID fpreg) { freeFPMask |= (1 << fpreg); } void putReg(FPRegisterID fpreg) { JS_ASSERT(!hasReg(fpreg)); putRegUnchecked(fpreg); } void takeReg(FPRegisterID fpreg) { JS_ASSERT(hasReg(fpreg)); freeFPMask &= ~(1 << fpreg); } bool operator ==(const FPRegisters &other) { return freeFPMask == other.freeFPMask; } uint32 freeFPMask; }; static const JSC::MacroAssembler::RegisterID JSFrameReg = Registers::JSFrameReg; } /* namespace mjit */ } /* namespace js */ #endif /* jsjaeger_regstate_h__ */