mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
454 lines
13 KiB
C++
454 lines
13 KiB
C++
/* -*- 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 <brendan@mozilla.org>
|
|
*
|
|
* Contributor(s):
|
|
* David Anderson <danderson@mozilla.com>
|
|
*
|
|
* 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__ */
|
|
|