diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /JavaScriptCore/assembler | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'JavaScriptCore/assembler')
21 files changed, 0 insertions, 15153 deletions
diff --git a/JavaScriptCore/assembler/ARMAssembler.cpp b/JavaScriptCore/assembler/ARMAssembler.cpp deleted file mode 100644 index 86a1c14..0000000 --- a/JavaScriptCore/assembler/ARMAssembler.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2009 University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 "config.h" - -#if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) - -#include "ARMAssembler.h" - -namespace JSC { - -// Patching helpers - -void ARMAssembler::patchConstantPoolLoad(void* loadAddr, void* constPoolAddr) -{ - ARMWord *ldr = reinterpret_cast<ARMWord*>(loadAddr); - ARMWord diff = reinterpret_cast<ARMWord*>(constPoolAddr) - ldr; - ARMWord index = (*ldr & 0xfff) >> 1; - - ASSERT(diff >= 1); - if (diff >= 2 || index > 0) { - diff = (diff + index - 2) * sizeof(ARMWord); - ASSERT(diff <= 0xfff); - *ldr = (*ldr & ~0xfff) | diff; - } else - *ldr = (*ldr & ~(0xfff | ARMAssembler::DT_UP)) | sizeof(ARMWord); -} - -// Handle immediates - -ARMWord ARMAssembler::getOp2(ARMWord imm) -{ - int rol; - - if (imm <= 0xff) - return OP2_IMM | imm; - - if ((imm & 0xff000000) == 0) { - imm <<= 8; - rol = 8; - } - else { - imm = (imm << 24) | (imm >> 8); - rol = 0; - } - - if ((imm & 0xff000000) == 0) { - imm <<= 8; - rol += 4; - } - - if ((imm & 0xf0000000) == 0) { - imm <<= 4; - rol += 2; - } - - if ((imm & 0xc0000000) == 0) { - imm <<= 2; - rol += 1; - } - - if ((imm & 0x00ffffff) == 0) - return OP2_IMM | (imm >> 24) | (rol << 8); - - return INVALID_IMM; -} - -int ARMAssembler::genInt(int reg, ARMWord imm, bool positive) -{ - // Step1: Search a non-immediate part - ARMWord mask; - ARMWord imm1; - ARMWord imm2; - int rol; - - mask = 0xff000000; - rol = 8; - while(1) { - if ((imm & mask) == 0) { - imm = (imm << rol) | (imm >> (32 - rol)); - rol = 4 + (rol >> 1); - break; - } - rol += 2; - mask >>= 2; - if (mask & 0x3) { - // rol 8 - imm = (imm << 8) | (imm >> 24); - mask = 0xff00; - rol = 24; - while (1) { - if ((imm & mask) == 0) { - imm = (imm << rol) | (imm >> (32 - rol)); - rol = (rol >> 1) - 8; - break; - } - rol += 2; - mask >>= 2; - if (mask & 0x3) - return 0; - } - break; - } - } - - ASSERT((imm & 0xff) == 0); - - if ((imm & 0xff000000) == 0) { - imm1 = OP2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8); - imm2 = OP2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8); - } else if (imm & 0xc0000000) { - imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); - imm <<= 8; - rol += 4; - - if ((imm & 0xff000000) == 0) { - imm <<= 8; - rol += 4; - } - - if ((imm & 0xf0000000) == 0) { - imm <<= 4; - rol += 2; - } - - if ((imm & 0xc0000000) == 0) { - imm <<= 2; - rol += 1; - } - - if ((imm & 0x00ffffff) == 0) - imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8); - else - return 0; - } else { - if ((imm & 0xf0000000) == 0) { - imm <<= 4; - rol += 2; - } - - if ((imm & 0xc0000000) == 0) { - imm <<= 2; - rol += 1; - } - - imm1 = OP2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8); - imm <<= 8; - rol += 4; - - if ((imm & 0xf0000000) == 0) { - imm <<= 4; - rol += 2; - } - - if ((imm & 0xc0000000) == 0) { - imm <<= 2; - rol += 1; - } - - if ((imm & 0x00ffffff) == 0) - imm2 = OP2_IMM | (imm >> 24) | ((rol & 0xf) << 8); - else - return 0; - } - - if (positive) { - mov_r(reg, imm1); - orr_r(reg, reg, imm2); - } else { - mvn_r(reg, imm1); - bic_r(reg, reg, imm2); - } - - return 1; -} - -ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert) -{ - ARMWord tmp; - - // Do it by 1 instruction - tmp = getOp2(imm); - if (tmp != INVALID_IMM) - return tmp; - - tmp = getOp2(~imm); - if (tmp != INVALID_IMM) { - if (invert) - return tmp | OP2_INV_IMM; - mvn_r(tmpReg, tmp); - return tmpReg; - } - - return encodeComplexImm(imm, tmpReg); -} - -void ARMAssembler::moveImm(ARMWord imm, int dest) -{ - ARMWord tmp; - - // Do it by 1 instruction - tmp = getOp2(imm); - if (tmp != INVALID_IMM) { - mov_r(dest, tmp); - return; - } - - tmp = getOp2(~imm); - if (tmp != INVALID_IMM) { - mvn_r(dest, tmp); - return; - } - - encodeComplexImm(imm, dest); -} - -ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest) -{ -#if WTF_ARM_ARCH_AT_LEAST(7) - ARMWord tmp = getImm16Op2(imm); - if (tmp != INVALID_IMM) { - movw_r(dest, tmp); - return dest; - } - movw_r(dest, getImm16Op2(imm & 0xffff)); - movt_r(dest, getImm16Op2(imm >> 16)); - return dest; -#else - // Do it by 2 instruction - if (genInt(dest, imm, true)) - return dest; - if (genInt(dest, ~imm, false)) - return dest; - - ldr_imm(dest, imm); - return dest; -#endif -} - -// Memory load/store helpers - -void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes) -{ - ARMWord transferFlag = bytes ? DT_BYTE : 0; - if (offset >= 0) { - if (offset <= 0xfff) - dtr_u(isLoad, srcDst, base, offset | transferFlag); - else if (offset <= 0xfffff) { - add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); - dtr_u(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff) | transferFlag); - } else { - moveImm(offset, ARMRegisters::S0); - dtr_ur(isLoad, srcDst, base, ARMRegisters::S0 | transferFlag); - } - } else { - offset = -offset; - if (offset <= 0xfff) - dtr_d(isLoad, srcDst, base, offset | transferFlag); - else if (offset <= 0xfffff) { - sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); - dtr_d(isLoad, srcDst, ARMRegisters::S0, (offset & 0xfff) | transferFlag); - } else { - moveImm(offset, ARMRegisters::S0); - dtr_dr(isLoad, srcDst, base, ARMRegisters::S0 | transferFlag); - } - } -} - -void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset) -{ - ARMWord op2; - - ASSERT(scale >= 0 && scale <= 3); - op2 = lsl(index, scale); - - if (offset >= 0 && offset <= 0xfff) { - add_r(ARMRegisters::S0, base, op2); - dtr_u(isLoad, srcDst, ARMRegisters::S0, offset); - return; - } - if (offset <= 0 && offset >= -0xfff) { - add_r(ARMRegisters::S0, base, op2); - dtr_d(isLoad, srcDst, ARMRegisters::S0, -offset); - return; - } - - ldr_un_imm(ARMRegisters::S0, offset); - add_r(ARMRegisters::S0, ARMRegisters::S0, op2); - dtr_ur(isLoad, srcDst, base, ARMRegisters::S0); -} - -void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset) -{ - if (offset & 0x3) { - if (offset <= 0x3ff && offset >= 0) { - fdtr_u(isLoad, srcDst, base, offset >> 2); - return; - } - if (offset <= 0x3ffff && offset >= 0) { - add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); - fdtr_u(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); - return; - } - offset = -offset; - - if (offset <= 0x3ff && offset >= 0) { - fdtr_d(isLoad, srcDst, base, offset >> 2); - return; - } - if (offset <= 0x3ffff && offset >= 0) { - sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); - fdtr_d(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); - return; - } - offset = -offset; - } - - ldr_un_imm(ARMRegisters::S0, offset); - add_r(ARMRegisters::S0, ARMRegisters::S0, base); - fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0); -} - -void* ARMAssembler::executableCopy(ExecutablePool* allocator) -{ - // 64-bit alignment is required for next constant pool and JIT code as well - m_buffer.flushWithoutBarrier(true); - if (m_buffer.uncheckedSize() & 0x7) - bkpt(0); - - char* data = reinterpret_cast<char*>(m_buffer.executableCopy(allocator)); - - for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { - // The last bit is set if the constant must be placed on constant pool. - int pos = (*iter) & (~0x1); - ARMWord* ldrAddr = reinterpret_cast_ptr<ARMWord*>(data + pos); - ARMWord* addr = getLdrImmAddress(ldrAddr); - if (*addr != InvalidBranchTarget) { - if (!(*iter & 1)) { - int diff = reinterpret_cast_ptr<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetching); - - if ((diff <= BOFFSET_MAX && diff >= BOFFSET_MIN)) { - *ldrAddr = B | getConditionalField(*ldrAddr) | (diff & BRANCH_MASK); - continue; - } - } - *addr = reinterpret_cast<ARMWord>(data + *addr); - } - } - - return data; -} - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) diff --git a/JavaScriptCore/assembler/ARMAssembler.h b/JavaScriptCore/assembler/ARMAssembler.h deleted file mode 100644 index 77ec60f..0000000 --- a/JavaScriptCore/assembler/ARMAssembler.h +++ /dev/null @@ -1,948 +0,0 @@ -/* - * Copyright (C) 2009, 2010 University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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. - */ - -#ifndef ARMAssembler_h -#define ARMAssembler_h - -#if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) - -#include "AssemblerBufferWithConstantPool.h" -#include <wtf/Assertions.h> -namespace JSC { - - typedef uint32_t ARMWord; - - namespace ARMRegisters { - typedef enum { - r0 = 0, - r1, - r2, - r3, S0 = r3, - r4, - r5, - r6, - r7, - r8, S1 = r8, - r9, - r10, - r11, - r12, - r13, sp = r13, - r14, lr = r14, - r15, pc = r15 - } RegisterID; - - typedef enum { - d0, - d1, - d2, - d3, SD0 = d3, - d4, - d5, - d6, - d7, - d8, - d9, - d10, - d11, - d12, - d13, - d14, - d15, - d16, - d17, - d18, - d19, - d20, - d21, - d22, - d23, - d24, - d25, - d26, - d27, - d28, - d29, - d30, - d31 - } FPRegisterID; - - } // namespace ARMRegisters - - class ARMAssembler { - public: - typedef ARMRegisters::RegisterID RegisterID; - typedef ARMRegisters::FPRegisterID FPRegisterID; - typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer; - typedef SegmentedVector<int, 64> Jumps; - - ARMAssembler() { } - - // ARM conditional constants - typedef enum { - EQ = 0x00000000, // Zero - NE = 0x10000000, // Non-zero - CS = 0x20000000, - CC = 0x30000000, - MI = 0x40000000, - PL = 0x50000000, - VS = 0x60000000, - VC = 0x70000000, - HI = 0x80000000, - LS = 0x90000000, - GE = 0xa0000000, - LT = 0xb0000000, - GT = 0xc0000000, - LE = 0xd0000000, - AL = 0xe0000000 - } Condition; - - // ARM instruction constants - enum { - AND = (0x0 << 21), - EOR = (0x1 << 21), - SUB = (0x2 << 21), - RSB = (0x3 << 21), - ADD = (0x4 << 21), - ADC = (0x5 << 21), - SBC = (0x6 << 21), - RSC = (0x7 << 21), - TST = (0x8 << 21), - TEQ = (0x9 << 21), - CMP = (0xa << 21), - CMN = (0xb << 21), - ORR = (0xc << 21), - MOV = (0xd << 21), - BIC = (0xe << 21), - MVN = (0xf << 21), - MUL = 0x00000090, - MULL = 0x00c00090, - VADD_F64 = 0x0e300b00, - VDIV_F64 = 0x0e800b00, - VSUB_F64 = 0x0e300b40, - VMUL_F64 = 0x0e200b00, - VCMP_F64 = 0x0eb40b40, - VSQRT_F64 = 0x0eb10bc0, - DTR = 0x05000000, - LDRH = 0x00100090, - STRH = 0x00000090, - STMDB = 0x09200000, - LDMIA = 0x08b00000, - FDTR = 0x0d000b00, - B = 0x0a000000, - BL = 0x0b000000, -#if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__) - BX = 0x012fff10, -#endif - VMOV_VFP = 0x0e000a10, - VMOV_ARM = 0x0e100a10, - VCVT_F64_S32 = 0x0eb80bc0, - VCVT_S32_F64 = 0x0ebd0b40, - VCVTR_S32_F64 = 0x0ebd0bc0, - VMRS_APSR = 0x0ef1fa10, -#if WTF_ARM_ARCH_AT_LEAST(5) - CLZ = 0x016f0f10, - BKPT = 0xe1200070, - BLX = 0x012fff30, -#endif -#if WTF_ARM_ARCH_AT_LEAST(7) - MOVW = 0x03000000, - MOVT = 0x03400000, -#endif - }; - - enum { - OP2_IMM = (1 << 25), - OP2_IMMh = (1 << 22), - OP2_INV_IMM = (1 << 26), - SET_CC = (1 << 20), - OP2_OFSREG = (1 << 25), - DT_UP = (1 << 23), - DT_BYTE = (1 << 22), - DT_WB = (1 << 21), - // This flag is inlcuded in LDR and STR - DT_PRE = (1 << 24), - HDT_UH = (1 << 5), - DT_LOAD = (1 << 20), - }; - - // Masks of ARM instructions - enum { - BRANCH_MASK = 0x00ffffff, - NONARM = 0xf0000000, - SDT_MASK = 0x0c000000, - SDT_OFFSET_MASK = 0xfff, - }; - - enum { - BOFFSET_MIN = -0x00800000, - BOFFSET_MAX = 0x007fffff, - SDT = 0x04000000, - }; - - enum { - padForAlign8 = 0x00, - padForAlign16 = 0x0000, - padForAlign32 = 0xe12fff7f // 'bkpt 0xffff' instruction. - }; - - static const ARMWord INVALID_IMM = 0xf0000000; - static const ARMWord InvalidBranchTarget = 0xffffffff; - static const int DefaultPrefetching = 2; - - class JmpSrc { - friend class ARMAssembler; - public: - JmpSrc() - : m_offset(-1) - { - } - - private: - JmpSrc(int offset) - : m_offset(offset) - { - } - - int m_offset; - }; - - class JmpDst { - friend class ARMAssembler; - public: - JmpDst() - : m_offset(-1) - , m_used(false) - { - } - - bool isUsed() const { return m_used; } - bool isSet() const { return (m_offset != -1); } - void used() { m_used = true; } - private: - JmpDst(int offset) - : m_offset(offset) - , m_used(false) - { - ASSERT(m_offset == offset); - } - - int m_offset : 31; - int m_used : 1; - }; - - // Instruction formating - - void emitInst(ARMWord op, int rd, int rn, ARMWord op2) - { - ASSERT(((op2 & ~OP2_IMM) <= 0xfff) || (((op2 & ~OP2_IMMh) <= 0xfff))); - m_buffer.putInt(op | RN(rn) | RD(rd) | op2); - } - - void emitDoublePrecisionInst(ARMWord op, int dd, int dn, int dm) - { - ASSERT((dd >= 0 && dd <= 31) && (dn >= 0 && dn <= 31) && (dm >= 0 && dm <= 31)); - m_buffer.putInt(op | ((dd & 0xf) << 12) | ((dd & 0x10) << (22 - 4)) - | ((dn & 0xf) << 16) | ((dn & 0x10) << (7 - 4)) - | (dm & 0xf) | ((dm & 0x10) << (5 - 4))); - } - - void emitSinglePrecisionInst(ARMWord op, int sd, int sn, int sm) - { - ASSERT((sd >= 0 && sd <= 31) && (sn >= 0 && sn <= 31) && (sm >= 0 && sm <= 31)); - m_buffer.putInt(op | ((sd >> 1) << 12) | ((sd & 0x1) << 22) - | ((sn >> 1) << 16) | ((sn & 0x1) << 7) - | (sm >> 1) | ((sm & 0x1) << 5)); - } - - void and_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | AND, rd, rn, op2); - } - - void ands_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | AND | SET_CC, rd, rn, op2); - } - - void eor_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | EOR, rd, rn, op2); - } - - void eors_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | EOR | SET_CC, rd, rn, op2); - } - - void sub_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | SUB, rd, rn, op2); - } - - void subs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | SUB | SET_CC, rd, rn, op2); - } - - void rsb_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | RSB, rd, rn, op2); - } - - void rsbs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | RSB | SET_CC, rd, rn, op2); - } - - void add_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | ADD, rd, rn, op2); - } - - void adds_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | ADD | SET_CC, rd, rn, op2); - } - - void adc_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | ADC, rd, rn, op2); - } - - void adcs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | ADC | SET_CC, rd, rn, op2); - } - - void sbc_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | SBC, rd, rn, op2); - } - - void sbcs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | SBC | SET_CC, rd, rn, op2); - } - - void rsc_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | RSC, rd, rn, op2); - } - - void rscs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | RSC | SET_CC, rd, rn, op2); - } - - void tst_r(int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | TST | SET_CC, 0, rn, op2); - } - - void teq_r(int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | TEQ | SET_CC, 0, rn, op2); - } - - void cmp_r(int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | CMP | SET_CC, 0, rn, op2); - } - - void cmn_r(int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | CMN | SET_CC, 0, rn, op2); - } - - void orr_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | ORR, rd, rn, op2); - } - - void orrs_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | ORR | SET_CC, rd, rn, op2); - } - - void mov_r(int rd, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | MOV, rd, ARMRegisters::r0, op2); - } - -#if WTF_ARM_ARCH_AT_LEAST(7) - void movw_r(int rd, ARMWord op2, Condition cc = AL) - { - ASSERT((op2 | 0xf0fff) == 0xf0fff); - m_buffer.putInt(static_cast<ARMWord>(cc) | MOVW | RD(rd) | op2); - } - - void movt_r(int rd, ARMWord op2, Condition cc = AL) - { - ASSERT((op2 | 0xf0fff) == 0xf0fff); - m_buffer.putInt(static_cast<ARMWord>(cc) | MOVT | RD(rd) | op2); - } -#endif - - void movs_r(int rd, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2); - } - - void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | BIC, rd, rn, op2); - } - - void bics_r(int rd, int rn, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | BIC | SET_CC, rd, rn, op2); - } - - void mvn_r(int rd, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | MVN, rd, ARMRegisters::r0, op2); - } - - void mvns_r(int rd, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2); - } - - void mul_r(int rd, int rn, int rm, Condition cc = AL) - { - m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | RN(rd) | RS(rn) | RM(rm)); - } - - void muls_r(int rd, int rn, int rm, Condition cc = AL) - { - m_buffer.putInt(static_cast<ARMWord>(cc) | MUL | SET_CC | RN(rd) | RS(rn) | RM(rm)); - } - - void mull_r(int rdhi, int rdlo, int rn, int rm, Condition cc = AL) - { - m_buffer.putInt(static_cast<ARMWord>(cc) | MULL | RN(rdhi) | RD(rdlo) | RS(rn) | RM(rm)); - } - - void vadd_f64_r(int dd, int dn, int dm, Condition cc = AL) - { - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VADD_F64, dd, dn, dm); - } - - void vdiv_f64_r(int dd, int dn, int dm, Condition cc = AL) - { - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VDIV_F64, dd, dn, dm); - } - - void vsub_f64_r(int dd, int dn, int dm, Condition cc = AL) - { - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VSUB_F64, dd, dn, dm); - } - - void vmul_f64_r(int dd, int dn, int dm, Condition cc = AL) - { - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VMUL_F64, dd, dn, dm); - } - - void vcmp_f64_r(int dd, int dm, Condition cc = AL) - { - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCMP_F64, dd, 0, dm); - } - - void vsqrt_f64_r(int dd, int dm, Condition cc = AL) - { - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VSQRT_F64, dd, 0, dm); - } - - void ldr_imm(int rd, ARMWord imm, Condition cc = AL) - { - m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true); - } - - void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL) - { - m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm); - } - - void dtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP, rd, rb, op2); - } - - void dtr_ur(bool isLoad, int rd, int rb, int rm, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | DT_UP | OP2_OFSREG, rd, rb, rm); - } - - void dtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0), rd, rb, op2); - } - - void dtr_dr(bool isLoad, int rd, int rb, int rm, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | DTR | (isLoad ? DT_LOAD : 0) | OP2_OFSREG, rd, rb, rm); - } - - void ldrh_r(int rd, int rn, int rm, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm); - } - - void ldrh_d(int rd, int rb, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_PRE, rd, rb, op2); - } - - void ldrh_u(int rd, int rb, ARMWord op2, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | LDRH | HDT_UH | DT_UP | DT_PRE, rd, rb, op2); - } - - void strh_r(int rn, int rm, int rd, Condition cc = AL) - { - emitInst(static_cast<ARMWord>(cc) | STRH | HDT_UH | DT_UP | DT_PRE, rd, rn, rm); - } - - void fdtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) - { - ASSERT(op2 <= 0xff); - emitInst(static_cast<ARMWord>(cc) | FDTR | DT_UP | (isLoad ? DT_LOAD : 0), rd, rb, op2); - } - - void fdtr_d(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) - { - ASSERT(op2 <= 0xff); - emitInst(static_cast<ARMWord>(cc) | FDTR | (isLoad ? DT_LOAD : 0), rd, rb, op2); - } - - void push_r(int reg, Condition cc = AL) - { - ASSERT(ARMWord(reg) <= 0xf); - m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4); - } - - void pop_r(int reg, Condition cc = AL) - { - ASSERT(ARMWord(reg) <= 0xf); - m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4); - } - - inline void poke_r(int reg, Condition cc = AL) - { - dtr_d(false, ARMRegisters::sp, 0, reg, cc); - } - - inline void peek_r(int reg, Condition cc = AL) - { - dtr_u(true, reg, ARMRegisters::sp, 0, cc); - } - - void vmov_vfp_r(int sn, int rt, Condition cc = AL) - { - ASSERT(rt <= 15); - emitSinglePrecisionInst(static_cast<ARMWord>(cc) | VMOV_VFP, rt << 1, sn, 0); - } - - void vmov_arm_r(int rt, int sn, Condition cc = AL) - { - ASSERT(rt <= 15); - emitSinglePrecisionInst(static_cast<ARMWord>(cc) | VMOV_ARM, rt << 1, sn, 0); - } - - void vcvt_f64_s32_r(int dd, int sm, Condition cc = AL) - { - ASSERT(!(sm & 0x1)); // sm must be divisible by 2 - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVT_F64_S32, dd, 0, (sm >> 1)); - } - - void vcvt_s32_f64_r(int sd, int dm, Condition cc = AL) - { - ASSERT(!(sd & 0x1)); // sd must be divisible by 2 - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVT_S32_F64, (sd >> 1), 0, dm); - } - - void vcvtr_s32_f64_r(int sd, int dm, Condition cc = AL) - { - ASSERT(!(sd & 0x1)); // sd must be divisible by 2 - emitDoublePrecisionInst(static_cast<ARMWord>(cc) | VCVTR_S32_F64, (sd >> 1), 0, dm); - } - - void vmrs_apsr(Condition cc = AL) - { - m_buffer.putInt(static_cast<ARMWord>(cc) | VMRS_APSR); - } - -#if WTF_ARM_ARCH_AT_LEAST(5) - void clz_r(int rd, int rm, Condition cc = AL) - { - m_buffer.putInt(static_cast<ARMWord>(cc) | CLZ | RD(rd) | RM(rm)); - } -#endif - - void bkpt(ARMWord value) - { -#if WTF_ARM_ARCH_AT_LEAST(5) - m_buffer.putInt(BKPT | ((value & 0xff0) << 4) | (value & 0xf)); -#else - // Cannot access to Zero memory address - dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0); -#endif - } - - void bx(int rm, Condition cc = AL) - { -#if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__) - emitInst(static_cast<ARMWord>(cc) | BX, 0, 0, RM(rm)); -#else - mov_r(ARMRegisters::pc, RM(rm), cc); -#endif - } - - JmpSrc blx(int rm, Condition cc = AL) - { -#if WTF_ARM_ARCH_AT_LEAST(5) - emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm)); -#else - ASSERT(rm != 14); - ensureSpace(2 * sizeof(ARMWord), 0); - mov_r(ARMRegisters::lr, ARMRegisters::pc, cc); - bx(rm, cc); -#endif - return JmpSrc(m_buffer.uncheckedSize()); - } - - static ARMWord lsl(int reg, ARMWord value) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(value <= 0x1f); - return reg | (value << 7) | 0x00; - } - - static ARMWord lsr(int reg, ARMWord value) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(value <= 0x1f); - return reg | (value << 7) | 0x20; - } - - static ARMWord asr(int reg, ARMWord value) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(value <= 0x1f); - return reg | (value << 7) | 0x40; - } - - static ARMWord lsl_r(int reg, int shiftReg) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(shiftReg <= ARMRegisters::pc); - return reg | (shiftReg << 8) | 0x10; - } - - static ARMWord lsr_r(int reg, int shiftReg) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(shiftReg <= ARMRegisters::pc); - return reg | (shiftReg << 8) | 0x30; - } - - static ARMWord asr_r(int reg, int shiftReg) - { - ASSERT(reg <= ARMRegisters::pc); - ASSERT(shiftReg <= ARMRegisters::pc); - return reg | (shiftReg << 8) | 0x50; - } - - // General helpers - - int size() - { - return m_buffer.size(); - } - - void ensureSpace(int insnSpace, int constSpace) - { - m_buffer.ensureSpace(insnSpace, constSpace); - } - - int sizeOfConstantPool() - { - return m_buffer.sizeOfConstantPool(); - } - - JmpDst label() - { - return JmpDst(m_buffer.size()); - } - - JmpDst align(int alignment) - { - while (!m_buffer.isAligned(alignment)) - mov_r(ARMRegisters::r0, ARMRegisters::r0); - - return label(); - } - - JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0) - { - ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); - m_jumps.append(m_buffer.uncheckedSize() | (useConstantPool & 0x1)); - ldr_un_imm(rd, InvalidBranchTarget, cc); - return JmpSrc(m_buffer.uncheckedSize()); - } - - JmpSrc jmp(Condition cc = AL, int useConstantPool = 0) - { - return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool); - } - - void* executableCopy(ExecutablePool* allocator); - - // Patching helpers - - static ARMWord* getLdrImmAddress(ARMWord* insn) - { -#if WTF_ARM_ARCH_AT_LEAST(5) - // Check for call - if ((*insn & 0x0f7f0000) != 0x051f0000) { - // Must be BLX - ASSERT((*insn & 0x012fff30) == 0x012fff30); - insn--; - } -#endif - // Must be an ldr ..., [pc +/- imm] - ASSERT((*insn & 0x0f7f0000) == 0x051f0000); - - ARMWord addr = reinterpret_cast<ARMWord>(insn) + DefaultPrefetching * sizeof(ARMWord); - if (*insn & DT_UP) - return reinterpret_cast<ARMWord*>(addr + (*insn & SDT_OFFSET_MASK)); - return reinterpret_cast<ARMWord*>(addr - (*insn & SDT_OFFSET_MASK)); - } - - static ARMWord* getLdrImmAddressOnPool(ARMWord* insn, uint32_t* constPool) - { - // Must be an ldr ..., [pc +/- imm] - ASSERT((*insn & 0x0f7f0000) == 0x051f0000); - - if (*insn & 0x1) - return reinterpret_cast<ARMWord*>(constPool + ((*insn & SDT_OFFSET_MASK) >> 1)); - return getLdrImmAddress(insn); - } - - static void patchPointerInternal(intptr_t from, void* to) - { - ARMWord* insn = reinterpret_cast<ARMWord*>(from); - ARMWord* addr = getLdrImmAddress(insn); - *addr = reinterpret_cast<ARMWord>(to); - } - - static ARMWord patchConstantPoolLoad(ARMWord load, ARMWord value) - { - value = (value << 1) + 1; - ASSERT(!(value & ~0xfff)); - return (load & ~0xfff) | value; - } - - static void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr); - - // Patch pointers - - static void linkPointer(void* code, JmpDst from, void* to) - { - patchPointerInternal(reinterpret_cast<intptr_t>(code) + from.m_offset, to); - } - - static void repatchInt32(void* from, int32_t to) - { - patchPointerInternal(reinterpret_cast<intptr_t>(from), reinterpret_cast<void*>(to)); - } - - static void repatchPointer(void* from, void* to) - { - patchPointerInternal(reinterpret_cast<intptr_t>(from), to); - } - - static void repatchLoadPtrToLEA(void* from) - { - // On arm, this is a patch from LDR to ADD. It is restricted conversion, - // from special case to special case, altough enough for its purpose - ARMWord* insn = reinterpret_cast<ARMWord*>(from); - ASSERT((*insn & 0x0ff00f00) == 0x05900000); - - *insn = (*insn & 0xf00ff0ff) | 0x02800000; - ExecutableAllocator::cacheFlush(insn, sizeof(ARMWord)); - } - - // Linkers - static intptr_t getAbsoluteJumpAddress(void* base, int offset = 0) - { - return reinterpret_cast<intptr_t>(base) + offset - sizeof(ARMWord); - } - - void linkJump(JmpSrc from, JmpDst to) - { - ARMWord* insn = reinterpret_cast<ARMWord*>(getAbsoluteJumpAddress(m_buffer.data(), from.m_offset)); - ARMWord* addr = getLdrImmAddressOnPool(insn, m_buffer.poolAddress()); - *addr = static_cast<ARMWord>(to.m_offset); - } - - static void linkJump(void* code, JmpSrc from, void* to) - { - patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to); - } - - static void relinkJump(void* from, void* to) - { - patchPointerInternal(getAbsoluteJumpAddress(from), to); - } - - static void linkCall(void* code, JmpSrc from, void* to) - { - patchPointerInternal(getAbsoluteJumpAddress(code, from.m_offset), to); - } - - static void relinkCall(void* from, void* to) - { - patchPointerInternal(getAbsoluteJumpAddress(from), to); - } - - // Address operations - - static void* getRelocatedAddress(void* code, JmpSrc jump) - { - return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + jump.m_offset); - } - - static void* getRelocatedAddress(void* code, JmpDst label) - { - return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset); - } - - // Address differences - - static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to) - { - return to.m_offset - from.m_offset; - } - - static int getDifferenceBetweenLabels(JmpDst from, JmpDst to) - { - return to.m_offset - from.m_offset; - } - - static unsigned getCallReturnOffset(JmpSrc call) - { - return call.m_offset; - } - - // Handle immediates - - static ARMWord getOp2Byte(ARMWord imm) - { - ASSERT(imm <= 0xff); - return OP2_IMMh | (imm & 0x0f) | ((imm & 0xf0) << 4) ; - } - - static ARMWord getOp2(ARMWord imm); - -#if WTF_ARM_ARCH_AT_LEAST(7) - static ARMWord getImm16Op2(ARMWord imm) - { - if (imm <= 0xffff) - return (imm & 0xf000) << 4 | (imm & 0xfff); - return INVALID_IMM; - } -#endif - ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false); - void moveImm(ARMWord imm, int dest); - ARMWord encodeComplexImm(ARMWord imm, int dest); - - ARMWord getOffsetForHalfwordDataTransfer(ARMWord imm, int tmpReg) - { - // Encode immediate data in the instruction if it is possible - if (imm <= 0xff) - return getOp2Byte(imm); - // Otherwise, store the data in a temporary register - return encodeComplexImm(imm, tmpReg); - } - - // Memory load/store helpers - - void dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, int32_t offset, bool bytes = false); - void baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset); - void doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset); - - // Constant pool hnadlers - - static ARMWord placeConstantPoolBarrier(int offset) - { - offset = (offset - sizeof(ARMWord)) >> 2; - ASSERT((offset <= BOFFSET_MAX && offset >= BOFFSET_MIN)); - return AL | B | (offset & BRANCH_MASK); - } - - private: - ARMWord RM(int reg) - { - ASSERT(reg <= ARMRegisters::pc); - return reg; - } - - ARMWord RS(int reg) - { - ASSERT(reg <= ARMRegisters::pc); - return reg << 8; - } - - ARMWord RD(int reg) - { - ASSERT(reg <= ARMRegisters::pc); - return reg << 12; - } - - ARMWord RN(int reg) - { - ASSERT(reg <= ARMRegisters::pc); - return reg << 16; - } - - static ARMWord getConditionalField(ARMWord i) - { - return i & 0xf0000000; - } - - int genInt(int reg, ARMWord imm, bool positive); - - ARMBuffer m_buffer; - Jumps m_jumps; - }; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) - -#endif // ARMAssembler_h diff --git a/JavaScriptCore/assembler/ARMv7Assembler.cpp b/JavaScriptCore/assembler/ARMv7Assembler.cpp deleted file mode 100644 index 7aa1f10..0000000 --- a/JavaScriptCore/assembler/ARMv7Assembler.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "config.h" - -#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) - -#include "ARMv7Assembler.h" - -namespace JSC { - -const int ARMv7Assembler::JumpSizes[] = { 0xffffffff, sizeof(uint16_t), sizeof(uint16_t), - 2 * sizeof(uint16_t), 2 * sizeof(uint16_t), 3 * sizeof(uint16_t), 5 * sizeof(uint16_t), 6 * sizeof(uint16_t) }; -const int ARMv7Assembler::JumpPaddingSizes[] = { 0, 5 * sizeof(uint16_t), 6 * sizeof(uint16_t), - 5 * sizeof(uint16_t), 6 * sizeof(uint16_t) }; - -} - -#endif diff --git a/JavaScriptCore/assembler/ARMv7Assembler.h b/JavaScriptCore/assembler/ARMv7Assembler.h deleted file mode 100644 index b0fcd06..0000000 --- a/JavaScriptCore/assembler/ARMv7Assembler.h +++ /dev/null @@ -1,2358 +0,0 @@ -/* - * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 University of Szeged - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef ARMAssembler_h -#define ARMAssembler_h - -#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) - -#include "AssemblerBuffer.h" -#include <wtf/Assertions.h> -#include <wtf/Vector.h> -#include <stdint.h> - -namespace JSC { - -namespace ARMRegisters { - typedef enum { - r0, - r1, - r2, - r3, - r4, - r5, - r6, - r7, wr = r7, // thumb work register - r8, - r9, sb = r9, // static base - r10, sl = r10, // stack limit - r11, fp = r11, // frame pointer - r12, ip = r12, - r13, sp = r13, - r14, lr = r14, - r15, pc = r15, - } RegisterID; - - typedef enum { - s0, - s1, - s2, - s3, - s4, - s5, - s6, - s7, - s8, - s9, - s10, - s11, - s12, - s13, - s14, - s15, - s16, - s17, - s18, - s19, - s20, - s21, - s22, - s23, - s24, - s25, - s26, - s27, - s28, - s29, - s30, - s31, - } FPSingleRegisterID; - - typedef enum { - d0, - d1, - d2, - d3, - d4, - d5, - d6, - d7, - d8, - d9, - d10, - d11, - d12, - d13, - d14, - d15, - d16, - d17, - d18, - d19, - d20, - d21, - d22, - d23, - d24, - d25, - d26, - d27, - d28, - d29, - d30, - d31, - } FPDoubleRegisterID; - - typedef enum { - q0, - q1, - q2, - q3, - q4, - q5, - q6, - q7, - q8, - q9, - q10, - q11, - q12, - q13, - q14, - q15, - q16, - q17, - q18, - q19, - q20, - q21, - q22, - q23, - q24, - q25, - q26, - q27, - q28, - q29, - q30, - q31, - } FPQuadRegisterID; - - inline FPSingleRegisterID asSingle(FPDoubleRegisterID reg) - { - ASSERT(reg < d16); - return (FPSingleRegisterID)(reg << 1); - } - - inline FPDoubleRegisterID asDouble(FPSingleRegisterID reg) - { - ASSERT(!(reg & 1)); - return (FPDoubleRegisterID)(reg >> 1); - } -} - -class ARMv7Assembler; -class ARMThumbImmediate { - friend class ARMv7Assembler; - - typedef uint8_t ThumbImmediateType; - static const ThumbImmediateType TypeInvalid = 0; - static const ThumbImmediateType TypeEncoded = 1; - static const ThumbImmediateType TypeUInt16 = 2; - - typedef union { - int16_t asInt; - struct { - unsigned imm8 : 8; - unsigned imm3 : 3; - unsigned i : 1; - unsigned imm4 : 4; - }; - // If this is an encoded immediate, then it may describe a shift, or a pattern. - struct { - unsigned shiftValue7 : 7; - unsigned shiftAmount : 5; - }; - struct { - unsigned immediate : 8; - unsigned pattern : 4; - }; - } ThumbImmediateValue; - - // byte0 contains least significant bit; not using an array to make client code endian agnostic. - typedef union { - int32_t asInt; - struct { - uint8_t byte0; - uint8_t byte1; - uint8_t byte2; - uint8_t byte3; - }; - } PatternBytes; - - ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N) - { - if (value & ~((1 << N) - 1)) /* check for any of the top N bits (of 2N bits) are set */ - value >>= N; /* if any were set, lose the bottom N */ - else /* if none of the top N bits are set, */ - zeros += N; /* then we have identified N leading zeros */ - } - - static int32_t countLeadingZeros(uint32_t value) - { - if (!value) - return 32; - - int32_t zeros = 0; - countLeadingZerosPartial(value, zeros, 16); - countLeadingZerosPartial(value, zeros, 8); - countLeadingZerosPartial(value, zeros, 4); - countLeadingZerosPartial(value, zeros, 2); - countLeadingZerosPartial(value, zeros, 1); - return zeros; - } - - ARMThumbImmediate() - : m_type(TypeInvalid) - { - m_value.asInt = 0; - } - - ARMThumbImmediate(ThumbImmediateType type, ThumbImmediateValue value) - : m_type(type) - , m_value(value) - { - } - - ARMThumbImmediate(ThumbImmediateType type, uint16_t value) - : m_type(TypeUInt16) - { - // Make sure this constructor is only reached with type TypeUInt16; - // this extra parameter makes the code a little clearer by making it - // explicit at call sites which type is being constructed - ASSERT_UNUSED(type, type == TypeUInt16); - - m_value.asInt = value; - } - -public: - static ARMThumbImmediate makeEncodedImm(uint32_t value) - { - ThumbImmediateValue encoding; - encoding.asInt = 0; - - // okay, these are easy. - if (value < 256) { - encoding.immediate = value; - encoding.pattern = 0; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - int32_t leadingZeros = countLeadingZeros(value); - // if there were 24 or more leading zeros, then we'd have hit the (value < 256) case. - ASSERT(leadingZeros < 24); - - // Given a number with bit fields Z:B:C, where count(Z)+count(B)+count(C) == 32, - // Z are the bits known zero, B is the 8-bit immediate, C are the bits to check for - // zero. count(B) == 8, so the count of bits to be checked is 24 - count(Z). - int32_t rightShiftAmount = 24 - leadingZeros; - if (value == ((value >> rightShiftAmount) << rightShiftAmount)) { - // Shift the value down to the low byte position. The assign to - // shiftValue7 drops the implicit top bit. - encoding.shiftValue7 = value >> rightShiftAmount; - // The endoded shift amount is the magnitude of a right rotate. - encoding.shiftAmount = 8 + leadingZeros; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - PatternBytes bytes; - bytes.asInt = value; - - if ((bytes.byte0 == bytes.byte1) && (bytes.byte0 == bytes.byte2) && (bytes.byte0 == bytes.byte3)) { - encoding.immediate = bytes.byte0; - encoding.pattern = 3; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - if ((bytes.byte0 == bytes.byte2) && !(bytes.byte1 | bytes.byte3)) { - encoding.immediate = bytes.byte0; - encoding.pattern = 1; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - if ((bytes.byte1 == bytes.byte3) && !(bytes.byte0 | bytes.byte2)) { - encoding.immediate = bytes.byte1; - encoding.pattern = 2; - return ARMThumbImmediate(TypeEncoded, encoding); - } - - return ARMThumbImmediate(); - } - - static ARMThumbImmediate makeUInt12(int32_t value) - { - return (!(value & 0xfffff000)) - ? ARMThumbImmediate(TypeUInt16, (uint16_t)value) - : ARMThumbImmediate(); - } - - static ARMThumbImmediate makeUInt12OrEncodedImm(int32_t value) - { - // If this is not a 12-bit unsigned it, try making an encoded immediate. - return (!(value & 0xfffff000)) - ? ARMThumbImmediate(TypeUInt16, (uint16_t)value) - : makeEncodedImm(value); - } - - // The 'make' methods, above, return a !isValid() value if the argument - // cannot be represented as the requested type. This methods is called - // 'get' since the argument can always be represented. - static ARMThumbImmediate makeUInt16(uint16_t value) - { - return ARMThumbImmediate(TypeUInt16, value); - } - - bool isValid() - { - return m_type != TypeInvalid; - } - - // These methods rely on the format of encoded byte values. - bool isUInt3() { return !(m_value.asInt & 0xfff8); } - bool isUInt4() { return !(m_value.asInt & 0xfff0); } - bool isUInt5() { return !(m_value.asInt & 0xffe0); } - bool isUInt6() { return !(m_value.asInt & 0xffc0); } - bool isUInt7() { return !(m_value.asInt & 0xff80); } - bool isUInt8() { return !(m_value.asInt & 0xff00); } - bool isUInt9() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfe00); } - bool isUInt10() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xfc00); } - bool isUInt12() { return (m_type == TypeUInt16) && !(m_value.asInt & 0xf000); } - bool isUInt16() { return m_type == TypeUInt16; } - uint8_t getUInt3() { ASSERT(isUInt3()); return m_value.asInt; } - uint8_t getUInt4() { ASSERT(isUInt4()); return m_value.asInt; } - uint8_t getUInt5() { ASSERT(isUInt5()); return m_value.asInt; } - uint8_t getUInt6() { ASSERT(isUInt6()); return m_value.asInt; } - uint8_t getUInt7() { ASSERT(isUInt7()); return m_value.asInt; } - uint8_t getUInt8() { ASSERT(isUInt8()); return m_value.asInt; } - uint8_t getUInt9() { ASSERT(isUInt9()); return m_value.asInt; } - uint8_t getUInt10() { ASSERT(isUInt10()); return m_value.asInt; } - uint16_t getUInt12() { ASSERT(isUInt12()); return m_value.asInt; } - uint16_t getUInt16() { ASSERT(isUInt16()); return m_value.asInt; } - - bool isEncodedImm() { return m_type == TypeEncoded; } - -private: - ThumbImmediateType m_type; - ThumbImmediateValue m_value; -}; - -class VFPImmediate { -public: - VFPImmediate(double d) - : m_value(-1) - { - union { - uint64_t i; - double d; - } u; - - u.d = d; - - int sign = static_cast<int>(u.i >> 63); - int exponent = static_cast<int>(u.i >> 52) & 0x7ff; - uint64_t mantissa = u.i & 0x000fffffffffffffull; - - if ((exponent >= 0x3fc) && (exponent <= 0x403) && !(mantissa & 0x0000ffffffffffffull)) - m_value = (sign << 7) | ((exponent & 7) << 4) | (int)(mantissa >> 48); - } - - bool isValid() - { - return m_value != -1; - } - - uint8_t value() - { - return (uint8_t)m_value; - } - -private: - int m_value; -}; - -typedef enum { - SRType_LSL, - SRType_LSR, - SRType_ASR, - SRType_ROR, - - SRType_RRX = SRType_ROR -} ARMShiftType; - -class ARMv7Assembler; -class ShiftTypeAndAmount { - friend class ARMv7Assembler; - -public: - ShiftTypeAndAmount() - { - m_u.type = (ARMShiftType)0; - m_u.amount = 0; - } - - ShiftTypeAndAmount(ARMShiftType type, unsigned amount) - { - m_u.type = type; - m_u.amount = amount & 31; - } - - unsigned lo4() { return m_u.lo4; } - unsigned hi4() { return m_u.hi4; } - -private: - union { - struct { - unsigned lo4 : 4; - unsigned hi4 : 4; - }; - struct { - unsigned type : 2; - unsigned amount : 6; - }; - } m_u; -}; - -class ARMv7Assembler { -public: - ~ARMv7Assembler() - { - ASSERT(m_jumpsToLink.isEmpty()); - } - - typedef ARMRegisters::RegisterID RegisterID; - typedef ARMRegisters::FPSingleRegisterID FPSingleRegisterID; - typedef ARMRegisters::FPDoubleRegisterID FPDoubleRegisterID; - typedef ARMRegisters::FPQuadRegisterID FPQuadRegisterID; - - // (HS, LO, HI, LS) -> (AE, B, A, BE) - // (VS, VC) -> (O, NO) - typedef enum { - ConditionEQ, - ConditionNE, - ConditionHS, ConditionCS = ConditionHS, - ConditionLO, ConditionCC = ConditionLO, - ConditionMI, - ConditionPL, - ConditionVS, - ConditionVC, - ConditionHI, - ConditionLS, - ConditionGE, - ConditionLT, - ConditionGT, - ConditionLE, - ConditionAL, - ConditionInvalid - } Condition; - - enum JumpType { JumpFixed, JumpNoCondition, JumpCondition, JumpNoConditionFixedSize, JumpConditionFixedSize, JumpTypeCount }; - enum JumpLinkType { LinkInvalid, LinkJumpT1, LinkJumpT2, LinkJumpT3, - LinkJumpT4, LinkConditionalJumpT4, LinkBX, LinkConditionalBX, JumpLinkTypeCount }; - static const int JumpSizes[JumpLinkTypeCount]; - static const int JumpPaddingSizes[JumpTypeCount]; - class LinkRecord { - public: - LinkRecord(intptr_t from, intptr_t to, JumpType type, Condition condition) - : m_from(from) - , m_to(to) - , m_type(type) - , m_linkType(LinkInvalid) - , m_condition(condition) - { - } - intptr_t from() const { return m_from; } - void setFrom(intptr_t from) { m_from = from; } - intptr_t to() const { return m_to; } - JumpType type() const { return m_type; } - JumpLinkType linkType() const { return m_linkType; } - void setLinkType(JumpLinkType linkType) { ASSERT(m_linkType == LinkInvalid); m_linkType = linkType; } - Condition condition() const { return m_condition; } - private: - intptr_t m_from : 31; - intptr_t m_to : 31; - JumpType m_type : 3; - JumpLinkType m_linkType : 4; - Condition m_condition : 16; - }; - - class JmpSrc { - friend class ARMv7Assembler; - friend class ARMInstructionFormatter; - friend class LinkBuffer; - public: - JmpSrc() - : m_offset(-1) - { - } - - private: - JmpSrc(int offset, JumpType type) - : m_offset(offset) - , m_condition(ConditionInvalid) - , m_type(type) - { - ASSERT(m_type == JumpFixed || m_type == JumpNoCondition || m_type == JumpNoConditionFixedSize); - } - - JmpSrc(int offset, JumpType type, Condition condition) - : m_offset(offset) - , m_condition(condition) - , m_type(type) - { - ASSERT(m_type == JumpFixed || m_type == JumpCondition || m_type == JumpConditionFixedSize); - } - - int m_offset; - Condition m_condition : 16; - JumpType m_type : 16; - - }; - - class JmpDst { - friend class ARMv7Assembler; - friend class ARMInstructionFormatter; - friend class LinkBuffer; - public: - JmpDst() - : m_offset(-1) - , m_used(false) - { - } - - bool isUsed() const { return m_used; } - bool isSet() const { return (m_offset != -1); } - void used() { m_used = true; } - private: - JmpDst(int offset) - : m_offset(offset) - , m_used(false) - { - ASSERT(m_offset == offset); - } - - int m_offset : 31; - int m_used : 1; - }; - -private: - - // ARMv7, Appx-A.6.3 - bool BadReg(RegisterID reg) - { - return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc); - } - - uint32_t singleRegisterMask(FPSingleRegisterID rdNum, int highBitsShift, int lowBitShift) - { - uint32_t rdMask = (rdNum >> 1) << highBitsShift; - if (rdNum & 1) - rdMask |= 1 << lowBitShift; - return rdMask; - } - - uint32_t doubleRegisterMask(FPDoubleRegisterID rdNum, int highBitShift, int lowBitsShift) - { - uint32_t rdMask = (rdNum & 0xf) << lowBitsShift; - if (rdNum & 16) - rdMask |= 1 << highBitShift; - return rdMask; - } - - typedef enum { - OP_ADD_reg_T1 = 0x1800, - OP_SUB_reg_T1 = 0x1A00, - OP_ADD_imm_T1 = 0x1C00, - OP_SUB_imm_T1 = 0x1E00, - OP_MOV_imm_T1 = 0x2000, - OP_CMP_imm_T1 = 0x2800, - OP_ADD_imm_T2 = 0x3000, - OP_SUB_imm_T2 = 0x3800, - OP_AND_reg_T1 = 0x4000, - OP_EOR_reg_T1 = 0x4040, - OP_TST_reg_T1 = 0x4200, - OP_RSB_imm_T1 = 0x4240, - OP_CMP_reg_T1 = 0x4280, - OP_ORR_reg_T1 = 0x4300, - OP_MVN_reg_T1 = 0x43C0, - OP_ADD_reg_T2 = 0x4400, - OP_MOV_reg_T1 = 0x4600, - OP_BLX = 0x4700, - OP_BX = 0x4700, - OP_STR_reg_T1 = 0x5000, - OP_LDR_reg_T1 = 0x5800, - OP_LDRH_reg_T1 = 0x5A00, - OP_LDRB_reg_T1 = 0x5C00, - OP_STR_imm_T1 = 0x6000, - OP_LDR_imm_T1 = 0x6800, - OP_LDRB_imm_T1 = 0x7800, - OP_LDRH_imm_T1 = 0x8800, - OP_STR_imm_T2 = 0x9000, - OP_LDR_imm_T2 = 0x9800, - OP_ADD_SP_imm_T1 = 0xA800, - OP_ADD_SP_imm_T2 = 0xB000, - OP_SUB_SP_imm_T1 = 0xB080, - OP_BKPT = 0xBE00, - OP_IT = 0xBF00, - OP_NOP_T1 = 0xBF00, - } OpcodeID; - - typedef enum { - OP_B_T1 = 0xD000, - OP_B_T2 = 0xE000, - OP_AND_reg_T2 = 0xEA00, - OP_TST_reg_T2 = 0xEA10, - OP_ORR_reg_T2 = 0xEA40, - OP_ORR_S_reg_T2 = 0xEA50, - OP_ASR_imm_T1 = 0xEA4F, - OP_LSL_imm_T1 = 0xEA4F, - OP_LSR_imm_T1 = 0xEA4F, - OP_ROR_imm_T1 = 0xEA4F, - OP_MVN_reg_T2 = 0xEA6F, - OP_EOR_reg_T2 = 0xEA80, - OP_ADD_reg_T3 = 0xEB00, - OP_ADD_S_reg_T3 = 0xEB10, - OP_SUB_reg_T2 = 0xEBA0, - OP_SUB_S_reg_T2 = 0xEBB0, - OP_CMP_reg_T2 = 0xEBB0, - OP_VSTR = 0xED00, - OP_VLDR = 0xED10, - OP_VMOV_StoC = 0xEE00, - OP_VMOV_CtoS = 0xEE10, - OP_VMUL_T2 = 0xEE20, - OP_VADD_T2 = 0xEE30, - OP_VSUB_T2 = 0xEE30, - OP_VDIV = 0xEE80, - OP_VCMP_T1 = 0xEEB0, - OP_VCVT_FPIVFP = 0xEEB0, - OP_VMOV_IMM_T2 = 0xEEB0, - OP_VMRS = 0xEEB0, - OP_B_T3a = 0xF000, - OP_B_T4a = 0xF000, - OP_AND_imm_T1 = 0xF000, - OP_TST_imm = 0xF010, - OP_ORR_imm_T1 = 0xF040, - OP_MOV_imm_T2 = 0xF040, - OP_MVN_imm = 0xF060, - OP_EOR_imm_T1 = 0xF080, - OP_ADD_imm_T3 = 0xF100, - OP_ADD_S_imm_T3 = 0xF110, - OP_CMN_imm = 0xF110, - OP_SUB_imm_T3 = 0xF1A0, - OP_SUB_S_imm_T3 = 0xF1B0, - OP_CMP_imm_T2 = 0xF1B0, - OP_RSB_imm_T2 = 0xF1C0, - OP_ADD_imm_T4 = 0xF200, - OP_MOV_imm_T3 = 0xF240, - OP_SUB_imm_T4 = 0xF2A0, - OP_MOVT = 0xF2C0, - OP_NOP_T2a = 0xF3AF, - OP_LDRB_imm_T3 = 0xF810, - OP_LDRB_reg_T2 = 0xF810, - OP_LDRH_reg_T2 = 0xF830, - OP_LDRH_imm_T3 = 0xF830, - OP_STR_imm_T4 = 0xF840, - OP_STR_reg_T2 = 0xF840, - OP_LDR_imm_T4 = 0xF850, - OP_LDR_reg_T2 = 0xF850, - OP_LDRB_imm_T2 = 0xF890, - OP_LDRH_imm_T2 = 0xF8B0, - OP_STR_imm_T3 = 0xF8C0, - OP_LDR_imm_T3 = 0xF8D0, - OP_LSL_reg_T2 = 0xFA00, - OP_LSR_reg_T2 = 0xFA20, - OP_ASR_reg_T2 = 0xFA40, - OP_ROR_reg_T2 = 0xFA60, - OP_CLZ = 0xFAB0, - OP_SMULL_T1 = 0xFB80, - } OpcodeID1; - - typedef enum { - OP_VADD_T2b = 0x0A00, - OP_VDIVb = 0x0A00, - OP_VLDRb = 0x0A00, - OP_VMOV_IMM_T2b = 0x0A00, - OP_VMUL_T2b = 0x0A00, - OP_VSTRb = 0x0A00, - OP_VMOV_CtoSb = 0x0A10, - OP_VMOV_StoCb = 0x0A10, - OP_VMRSb = 0x0A10, - OP_VCMP_T1b = 0x0A40, - OP_VCVT_FPIVFPb = 0x0A40, - OP_VSUB_T2b = 0x0A40, - OP_NOP_T2b = 0x8000, - OP_B_T3b = 0x8000, - OP_B_T4b = 0x9000, - } OpcodeID2; - - struct FourFours { - FourFours(unsigned f3, unsigned f2, unsigned f1, unsigned f0) - { - m_u.f0 = f0; - m_u.f1 = f1; - m_u.f2 = f2; - m_u.f3 = f3; - } - - union { - unsigned value; - struct { - unsigned f0 : 4; - unsigned f1 : 4; - unsigned f2 : 4; - unsigned f3 : 4; - }; - } m_u; - }; - - class ARMInstructionFormatter; - - // false means else! - bool ifThenElseConditionBit(Condition condition, bool isIf) - { - return isIf ? (condition & 1) : !(condition & 1); - } - uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if, bool inst4if) - { - int mask = (ifThenElseConditionBit(condition, inst2if) << 3) - | (ifThenElseConditionBit(condition, inst3if) << 2) - | (ifThenElseConditionBit(condition, inst4if) << 1) - | 1; - ASSERT((condition != ConditionAL) || !(mask & (mask - 1))); - return (condition << 4) | mask; - } - uint8_t ifThenElse(Condition condition, bool inst2if, bool inst3if) - { - int mask = (ifThenElseConditionBit(condition, inst2if) << 3) - | (ifThenElseConditionBit(condition, inst3if) << 2) - | 2; - ASSERT((condition != ConditionAL) || !(mask & (mask - 1))); - return (condition << 4) | mask; - } - uint8_t ifThenElse(Condition condition, bool inst2if) - { - int mask = (ifThenElseConditionBit(condition, inst2if) << 3) - | 4; - ASSERT((condition != ConditionAL) || !(mask & (mask - 1))); - return (condition << 4) | mask; - } - - uint8_t ifThenElse(Condition condition) - { - int mask = 8; - return (condition << 4) | mask; - } - -public: - - void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isValid()); - - if (rn == ARMRegisters::sp) { - if (!(rd & 8) && imm.isUInt10()) { - m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2); - return; - } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) { - m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2); - return; - } - } else if (!((rd | rn) & 8)) { - if (imm.isUInt3()) { - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); - return; - } else if ((rd == rn) && imm.isUInt8()) { - m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8()); - return; - } - } - - if (imm.isEncodedImm()) - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T3, rn, rd, imm); - else { - ASSERT(imm.isUInt12()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_imm_T4, rn, rd, imm); - } - } - - void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // NOTE: In an IT block, add doesn't modify the flags register. - void add(RegisterID rd, RegisterID rn, RegisterID rm) - { - if (rd == rn) - m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rm, rd); - else if (rd == rm) - m_formatter.oneWordOp8RegReg143(OP_ADD_reg_T2, rn, rd); - else if (!((rd | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd); - else - add(rd, rn, rm, ShiftTypeAndAmount()); - } - - // Not allowed in an IT (if then) block. - void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isEncodedImm()); - - if (!((rd | rn) & 8)) { - if (imm.isUInt3()) { - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); - return; - } else if ((rd == rn) && imm.isUInt8()) { - m_formatter.oneWordOp5Reg3Imm8(OP_ADD_imm_T2, rd, imm.getUInt8()); - return; - } - } - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ADD_S_imm_T3, rn, rd, imm); - } - - // Not allowed in an IT (if then) block? - void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // Not allowed in an IT (if then) block. - void add_S(RegisterID rd, RegisterID rn, RegisterID rm) - { - if (!((rd | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_ADD_reg_T1, rm, rn, rd); - else - add_S(rd, rn, rm, ShiftTypeAndAmount()); - } - - void ARM_and(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(imm.isEncodedImm()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_AND_imm_T1, rn, rd, imm); - } - - void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_AND_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void ARM_and(RegisterID rd, RegisterID rn, RegisterID rm) - { - if ((rd == rn) && !((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rm, rd); - else if ((rd == rm) && !((rd | rn) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_AND_reg_T1, rn, rd); - else - ARM_and(rd, rn, rm, ShiftTypeAndAmount()); - } - - void asr(RegisterID rd, RegisterID rm, int32_t shiftAmount) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - ShiftTypeAndAmount shift(SRType_ASR, shiftAmount); - m_formatter.twoWordOp16FourFours(OP_ASR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void asr(RegisterID rd, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ASR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); - } - - // Only allowed in IT (if then) block if last instruction. - JmpSrc b(JumpType type) - { - m_formatter.twoWordOp16Op16(OP_B_T4a, OP_B_T4b); - return JmpSrc(m_formatter.size(), type); - } - - // Only allowed in IT (if then) block if last instruction. - JmpSrc blx(RegisterID rm, JumpType type) - { - ASSERT(rm != ARMRegisters::pc); - m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8); - return JmpSrc(m_formatter.size(), type); - } - - // Only allowed in IT (if then) block if last instruction. - JmpSrc bx(RegisterID rm, JumpType type, Condition condition) - { - m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0); - return JmpSrc(m_formatter.size(), type, condition); - } - - JmpSrc bx(RegisterID rm, JumpType type) - { - m_formatter.oneWordOp8RegReg143(OP_BX, rm, (RegisterID)0); - return JmpSrc(m_formatter.size(), type); - } - - void bkpt(uint8_t imm=0) - { - m_formatter.oneWordOp8Imm8(OP_BKPT, imm); - } - - void clz(RegisterID rd, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_CLZ, rm, FourFours(0xf, rd, 8, rm)); - } - - void cmn(RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isEncodedImm()); - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm); - } - - void cmp(RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isEncodedImm()); - - if (!(rn & 8) && imm.isUInt8()) - m_formatter.oneWordOp5Reg3Imm8(OP_CMP_imm_T1, rn, imm.getUInt8()); - else - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMP_imm_T2, rn, (RegisterID)0xf, imm); - } - - void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); - } - - void cmp(RegisterID rn, RegisterID rm) - { - if ((rn | rm) & 8) - cmp(rn, rm, ShiftTypeAndAmount()); - else - m_formatter.oneWordOp10Reg3Reg3(OP_CMP_reg_T1, rm, rn); - } - - // xor is not spelled with an 'e'. :-( - void eor(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(imm.isEncodedImm()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_EOR_imm_T1, rn, rd, imm); - } - - // xor is not spelled with an 'e'. :-( - void eor(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_EOR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // xor is not spelled with an 'e'. :-( - void eor(RegisterID rd, RegisterID rn, RegisterID rm) - { - if ((rd == rn) && !((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rm, rd); - else if ((rd == rm) && !((rd | rn) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_EOR_reg_T1, rn, rd); - else - eor(rd, rn, rm, ShiftTypeAndAmount()); - } - - void it(Condition cond) - { - m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond)); - } - - void it(Condition cond, bool inst2if) - { - m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if)); - } - - void it(Condition cond, bool inst2if, bool inst3if) - { - m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if)); - } - - void it(Condition cond, bool inst2if, bool inst3if, bool inst4if) - { - m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if)); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(imm.isUInt12()); - - if (!((rt | rn) & 8) && imm.isUInt7()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt); - else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) - m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2); - else - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12()); - } - - // If index is set, this is a regular offset or a pre-indexed load; - // if index is not set then is is a post-index load. - // - // If wback is set rn is updated - this is a pre or post index load, - // if wback is not set this is a regular offset memory access. - // - // (-255 <= offset <= 255) - // _reg = REG[rn] - // _tmp = _reg + offset - // MEM[index ? _tmp : _reg] = REG[rt] - // if (wback) REG[rn] = _tmp - void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(index || wback); - ASSERT(!wback | (rt != rn)); - - bool add = true; - if (offset < 0) { - add = false; - offset = -offset; - } - ASSERT((offset & ~0xff) == 0); - - offset |= (wback << 8); - offset |= (add << 9); - offset |= (index << 10); - offset |= (1 << 11); - - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(!BadReg(rm)); - ASSERT(shift <= 3); - - if (!shift && !((rt | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDR_reg_T1, rm, rn, rt); - else - m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm)); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(imm.isUInt12()); - - if (!((rt | rn) & 8) && imm.isUInt6()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt); - else - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12()); - } - - // If index is set, this is a regular offset or a pre-indexed load; - // if index is not set then is is a post-index load. - // - // If wback is set rn is updated - this is a pre or post index load, - // if wback is not set this is a regular offset memory access. - // - // (-255 <= offset <= 255) - // _reg = REG[rn] - // _tmp = _reg + offset - // MEM[index ? _tmp : _reg] = REG[rt] - // if (wback) REG[rn] = _tmp - void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(index || wback); - ASSERT(!wback | (rt != rn)); - - bool add = true; - if (offset < 0) { - add = false; - offset = -offset; - } - ASSERT((offset & ~0xff) == 0); - - offset |= (wback << 8); - offset |= (add << 9); - offset |= (index << 10); - offset |= (1 << 11); - - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T3, rn, rt, offset); - } - - void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) - { - ASSERT(!BadReg(rt)); // Memory hint - ASSERT(rn != ARMRegisters::pc); // LDRH (literal) - ASSERT(!BadReg(rm)); - ASSERT(shift <= 3); - - if (!shift && !((rt | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRH_reg_T1, rm, rn, rt); - else - m_formatter.twoWordOp12Reg4FourFours(OP_LDRH_reg_T2, rn, FourFours(rt, 0, shift, rm)); - } - - void ldrb(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(imm.isUInt12()); - - if (!((rt | rn) & 8) && imm.isUInt5()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRB_imm_T1, imm.getUInt5(), rn, rt); - else - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T2, rn, rt, imm.getUInt12()); - } - - void ldrb(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(index || wback); - ASSERT(!wback | (rt != rn)); - - bool add = true; - if (offset < 0) { - add = false; - offset = -offset; - } - - ASSERT(!(offset & ~0xff)); - - offset |= (wback << 8); - offset |= (add << 9); - offset |= (index << 10); - offset |= (1 << 11); - - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRB_imm_T3, rn, rt, offset); - } - - void ldrb(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift = 0) - { - ASSERT(rn != ARMRegisters::pc); // LDR (literal) - ASSERT(!BadReg(rm)); - ASSERT(shift <= 3); - - if (!shift && !((rt | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_LDRB_reg_T1, rm, rn, rt); - else - m_formatter.twoWordOp12Reg4FourFours(OP_LDRB_reg_T2, rn, FourFours(rt, 0, shift, rm)); - } - - void lsl(RegisterID rd, RegisterID rm, int32_t shiftAmount) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - ShiftTypeAndAmount shift(SRType_LSL, shiftAmount); - m_formatter.twoWordOp16FourFours(OP_LSL_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void lsl(RegisterID rd, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_LSL_reg_T2, rn, FourFours(0xf, rd, 0, rm)); - } - - void lsr(RegisterID rd, RegisterID rm, int32_t shiftAmount) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - ShiftTypeAndAmount shift(SRType_LSR, shiftAmount); - m_formatter.twoWordOp16FourFours(OP_LSR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void lsr(RegisterID rd, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_LSR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); - } - - void movT3(RegisterID rd, ARMThumbImmediate imm) - { - ASSERT(imm.isValid()); - ASSERT(!imm.isEncodedImm()); - ASSERT(!BadReg(rd)); - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T3, imm.m_value.imm4, rd, imm); - } - - void mov(RegisterID rd, ARMThumbImmediate imm) - { - ASSERT(imm.isValid()); - ASSERT(!BadReg(rd)); - - if ((rd < 8) && imm.isUInt8()) - m_formatter.oneWordOp5Reg3Imm8(OP_MOV_imm_T1, rd, imm.getUInt8()); - else if (imm.isEncodedImm()) - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOV_imm_T2, 0xf, rd, imm); - else - movT3(rd, imm); - } - - void mov(RegisterID rd, RegisterID rm) - { - m_formatter.oneWordOp8RegReg143(OP_MOV_reg_T1, rm, rd); - } - - void movt(RegisterID rd, ARMThumbImmediate imm) - { - ASSERT(imm.isUInt16()); - ASSERT(!BadReg(rd)); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MOVT, imm.m_value.imm4, rd, imm); - } - - void mvn(RegisterID rd, ARMThumbImmediate imm) - { - ASSERT(imm.isEncodedImm()); - ASSERT(!BadReg(rd)); - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_MVN_imm, 0xf, rd, imm); - } - - void mvn(RegisterID rd, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp16FourFours(OP_MVN_reg_T2, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void mvn(RegisterID rd, RegisterID rm) - { - if (!((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_MVN_reg_T1, rm, rd); - else - mvn(rd, rm, ShiftTypeAndAmount()); - } - - void neg(RegisterID rd, RegisterID rm) - { - ARMThumbImmediate zero = ARMThumbImmediate::makeUInt12(0); - sub(rd, zero, rm); - } - - void orr(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(imm.isEncodedImm()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_ORR_imm_T1, rn, rd, imm); - } - - void orr(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ORR_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void orr(RegisterID rd, RegisterID rn, RegisterID rm) - { - if ((rd == rn) && !((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd); - else if ((rd == rm) && !((rd | rn) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd); - else - orr(rd, rn, rm, ShiftTypeAndAmount()); - } - - void orr_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ORR_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void orr_S(RegisterID rd, RegisterID rn, RegisterID rm) - { - if ((rd == rn) && !((rd | rm) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rm, rd); - else if ((rd == rm) && !((rd | rn) & 8)) - m_formatter.oneWordOp10Reg3Reg3(OP_ORR_reg_T1, rn, rd); - else - orr_S(rd, rn, rm, ShiftTypeAndAmount()); - } - - void ror(RegisterID rd, RegisterID rm, int32_t shiftAmount) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rm)); - ShiftTypeAndAmount shift(SRType_ROR, shiftAmount); - m_formatter.twoWordOp16FourFours(OP_ROR_imm_T1, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - void ror(RegisterID rd, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rd)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_ROR_reg_T2, rn, FourFours(0xf, rd, 0, rm)); - } - - void smull(RegisterID rdLo, RegisterID rdHi, RegisterID rn, RegisterID rm) - { - ASSERT(!BadReg(rdLo)); - ASSERT(!BadReg(rdHi)); - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - ASSERT(rdLo != rdHi); - m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm)); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isUInt12()); - - if (!((rt | rn) & 8) && imm.isUInt7()) - m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt); - else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) - m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2); - else - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12()); - } - - // If index is set, this is a regular offset or a pre-indexed store; - // if index is not set then is is a post-index store. - // - // If wback is set rn is updated - this is a pre or post index store, - // if wback is not set this is a regular offset memory access. - // - // (-255 <= offset <= 255) - // _reg = REG[rn] - // _tmp = _reg + offset - // MEM[index ? _tmp : _reg] = REG[rt] - // if (wback) REG[rn] = _tmp - void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) - { - ASSERT(rt != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(index || wback); - ASSERT(!wback | (rt != rn)); - - bool add = true; - if (offset < 0) { - add = false; - offset = -offset; - } - ASSERT((offset & ~0xff) == 0); - - offset |= (wback << 8); - offset |= (add << 9); - offset |= (index << 10); - offset |= (1 << 11); - - m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset); - } - - // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. - void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) - { - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - ASSERT(shift <= 3); - - if (!shift && !((rt | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_STR_reg_T1, rm, rn, rt); - else - m_formatter.twoWordOp12Reg4FourFours(OP_STR_reg_T2, rn, FourFours(rt, 0, shift, rm)); - } - - void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isValid()); - - if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { - m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2); - return; - } else if (!((rd | rn) & 8)) { - if (imm.isUInt3()) { - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); - return; - } else if ((rd == rn) && imm.isUInt8()) { - m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8()); - return; - } - } - - if (imm.isEncodedImm()) - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T3, rn, rd, imm); - else { - ASSERT(imm.isUInt12()); - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_imm_T4, rn, rd, imm); - } - } - - void sub(RegisterID rd, ARMThumbImmediate imm, RegisterID rn) - { - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isValid()); - ASSERT(imm.isUInt12()); - - if (!((rd | rn) & 8) && !imm.getUInt12()) - m_formatter.oneWordOp10Reg3Reg3(OP_RSB_imm_T1, rn, rd); - else - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_RSB_imm_T2, rn, rd, imm); - } - - void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // NOTE: In an IT block, add doesn't modify the flags register. - void sub(RegisterID rd, RegisterID rn, RegisterID rm) - { - if (!((rd | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd); - else - sub(rd, rn, rm, ShiftTypeAndAmount()); - } - - // Not allowed in an IT (if then) block. - void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) - { - // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(imm.isValid()); - - if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { - m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2); - return; - } else if (!((rd | rn) & 8)) { - if (imm.isUInt3()) { - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_imm_T1, (RegisterID)imm.getUInt3(), rn, rd); - return; - } else if ((rd == rn) && imm.isUInt8()) { - m_formatter.oneWordOp5Reg3Imm8(OP_SUB_imm_T2, rd, imm.getUInt8()); - return; - } - } - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_SUB_S_imm_T3, rn, rd, imm); - } - - // Not allowed in an IT (if then) block? - void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); - ASSERT(rd != ARMRegisters::pc); - ASSERT(rn != ARMRegisters::pc); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); - } - - // Not allowed in an IT (if then) block. - void sub_S(RegisterID rd, RegisterID rn, RegisterID rm) - { - if (!((rd | rn | rm) & 8)) - m_formatter.oneWordOp7Reg3Reg3Reg3(OP_SUB_reg_T1, rm, rn, rd); - else - sub_S(rd, rn, rm, ShiftTypeAndAmount()); - } - - void tst(RegisterID rn, ARMThumbImmediate imm) - { - ASSERT(!BadReg(rn)); - ASSERT(imm.isEncodedImm()); - - m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_TST_imm, rn, (RegisterID)0xf, imm); - } - - void tst(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) - { - ASSERT(!BadReg(rn)); - ASSERT(!BadReg(rm)); - m_formatter.twoWordOp12Reg4FourFours(OP_TST_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); - } - - void tst(RegisterID rn, RegisterID rm) - { - if ((rn | rm) & 8) - tst(rn, rm, ShiftTypeAndAmount()); - else - m_formatter.oneWordOp10Reg3Reg3(OP_TST_reg_T1, rm, rn); - } - - void vadd_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm) - { - m_formatter.vfpOp(OP_VADD_T2, OP_VADD_T2b, true, rn, rd, rm); - } - - void vcmp_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rm) - { - m_formatter.vfpOp(OP_VCMP_T1, OP_VCMP_T1b, true, VFPOperand(4), rd, rm); - } - - void vcvt_F64_S32(FPDoubleRegisterID rd, FPSingleRegisterID rm) - { - // boolean values are 64bit (toInt, unsigned, roundZero) - m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(false, false, false), rd, rm); - } - - void vcvtr_S32_F64(FPSingleRegisterID rd, FPDoubleRegisterID rm) - { - // boolean values are 64bit (toInt, unsigned, roundZero) - m_formatter.vfpOp(OP_VCVT_FPIVFP, OP_VCVT_FPIVFPb, true, vcvtOp(true, false, true), rd, rm); - } - - void vdiv_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm) - { - m_formatter.vfpOp(OP_VDIV, OP_VDIVb, true, rn, rd, rm); - } - - void vldr(FPDoubleRegisterID rd, RegisterID rn, int32_t imm) - { - m_formatter.vfpMemOp(OP_VLDR, OP_VLDRb, true, rn, rd, imm); - } - - void vmov_F64_0(FPDoubleRegisterID rd) - { - m_formatter.vfpOp(OP_VMOV_IMM_T2, OP_VMOV_IMM_T2b, true, VFPOperand(0), rd, VFPOperand(0)); - } - - void vmov(RegisterID rd, FPSingleRegisterID rn) - { - ASSERT(!BadReg(rd)); - m_formatter.vfpOp(OP_VMOV_CtoS, OP_VMOV_CtoSb, false, rn, rd, VFPOperand(0)); - } - - void vmov(FPSingleRegisterID rd, RegisterID rn) - { - ASSERT(!BadReg(rn)); - m_formatter.vfpOp(OP_VMOV_StoC, OP_VMOV_StoCb, false, rd, rn, VFPOperand(0)); - } - - void vmrs(RegisterID reg = ARMRegisters::pc) - { - ASSERT(reg != ARMRegisters::sp); - m_formatter.vfpOp(OP_VMRS, OP_VMRSb, false, VFPOperand(1), VFPOperand(0x10 | reg), VFPOperand(0)); - } - - void vmul_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm) - { - m_formatter.vfpOp(OP_VMUL_T2, OP_VMUL_T2b, true, rn, rd, rm); - } - - void vstr(FPDoubleRegisterID rd, RegisterID rn, int32_t imm) - { - m_formatter.vfpMemOp(OP_VSTR, OP_VSTRb, true, rn, rd, imm); - } - - void vsub_F64(FPDoubleRegisterID rd, FPDoubleRegisterID rn, FPDoubleRegisterID rm) - { - m_formatter.vfpOp(OP_VSUB_T2, OP_VSUB_T2b, true, rn, rd, rm); - } - - JmpDst label() - { - return JmpDst(m_formatter.size()); - } - - JmpDst align(int alignment) - { - while (!m_formatter.isAligned(alignment)) - bkpt(); - - return label(); - } - - static void* getRelocatedAddress(void* code, JmpSrc jump) - { - ASSERT(jump.m_offset != -1); - - return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset); - } - - static void* getRelocatedAddress(void* code, JmpDst destination) - { - ASSERT(destination.m_offset != -1); - - return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset); - } - - static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst) - { - return dst.m_offset - src.m_offset; - } - - static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst) - { - return dst.m_offset - src.m_offset; - } - - static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst) - { - return dst.m_offset - src.m_offset; - } - - int executableOffsetFor(int location) - { - if (!location) - return 0; - return static_cast<int32_t*>(m_formatter.data())[location / sizeof(int32_t) - 1]; - } - - int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return JumpPaddingSizes[jumpType] - JumpSizes[jumpLinkType]; } - - // Assembler admin methods: - - size_t size() const - { - return m_formatter.size(); - } - - static bool linkRecordSourceComparator(const LinkRecord& a, const LinkRecord& b) - { - return a.from() < b.from(); - } - - bool canCompact(JumpType jumpType) - { - // The following cannot be compacted: - // JumpFixed: represents custom jump sequence - // JumpNoConditionFixedSize: represents unconditional jump that must remain a fixed size - // JumpConditionFixedSize: represents conditional jump that must remain a fixed size - return (jumpType == JumpNoCondition) || (jumpType == JumpCondition); - } - - JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) - { - if (jumpType == JumpFixed) - return LinkInvalid; - - // for patchable jump we must leave space for the longest code sequence - if (jumpType == JumpNoConditionFixedSize) - return LinkBX; - if (jumpType == JumpConditionFixedSize) - return LinkConditionalBX; - - const int paddingSize = JumpPaddingSizes[jumpType]; - bool mayTriggerErrata = false; - - if (jumpType == JumpCondition) { - // 2-byte conditional T1 - const uint16_t* jumpT1Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkJumpT1])); - if (canBeJumpT1(jumpT1Location, to)) - return LinkJumpT1; - // 4-byte conditional T3 - const uint16_t* jumpT3Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkJumpT3])); - if (canBeJumpT3(jumpT3Location, to, mayTriggerErrata)) { - if (!mayTriggerErrata) - return LinkJumpT3; - } - // 4-byte conditional T4 with IT - const uint16_t* conditionalJumpT4Location = - reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkConditionalJumpT4])); - if (canBeJumpT4(conditionalJumpT4Location, to, mayTriggerErrata)) { - if (!mayTriggerErrata) - return LinkConditionalJumpT4; - } - } else { - // 2-byte unconditional T2 - const uint16_t* jumpT2Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkJumpT2])); - if (canBeJumpT2(jumpT2Location, to)) - return LinkJumpT2; - // 4-byte unconditional T4 - const uint16_t* jumpT4Location = reinterpret_cast<const uint16_t*>(from - (paddingSize - JumpSizes[LinkJumpT4])); - if (canBeJumpT4(jumpT4Location, to, mayTriggerErrata)) { - if (!mayTriggerErrata) - return LinkJumpT4; - } - // use long jump sequence - return LinkBX; - } - - ASSERT(jumpType == JumpCondition); - return LinkConditionalBX; - } - - JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) - { - JumpLinkType linkType = computeJumpType(record.type(), from, to); - record.setLinkType(linkType); - return linkType; - } - - void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) - { - int32_t ptr = regionStart / sizeof(int32_t); - const int32_t end = regionEnd / sizeof(int32_t); - int32_t* offsets = static_cast<int32_t*>(m_formatter.data()); - while (ptr < end) - offsets[ptr++] = offset; - } - - Vector<LinkRecord>& jumpsToLink() - { - std::sort(m_jumpsToLink.begin(), m_jumpsToLink.end(), linkRecordSourceComparator); - return m_jumpsToLink; - } - - void link(LinkRecord& record, uint8_t* from, uint8_t* to) - { - switch (record.linkType()) { - case LinkJumpT1: - linkJumpT1(record.condition(), reinterpret_cast<uint16_t*>(from), to); - break; - case LinkJumpT2: - linkJumpT2(reinterpret_cast<uint16_t*>(from), to); - break; - case LinkJumpT3: - linkJumpT3(record.condition(), reinterpret_cast<uint16_t*>(from), to); - break; - case LinkJumpT4: - linkJumpT4(reinterpret_cast<uint16_t*>(from), to); - break; - case LinkConditionalJumpT4: - linkConditionalJumpT4(record.condition(), reinterpret_cast<uint16_t*>(from), to); - break; - case LinkConditionalBX: - linkConditionalBX(record.condition(), reinterpret_cast<uint16_t*>(from), to); - break; - case LinkBX: - linkBX(reinterpret_cast<uint16_t*>(from), to); - break; - default: - ASSERT_NOT_REACHED(); - break; - } - } - - void* unlinkedCode() { return m_formatter.data(); } - - static unsigned getCallReturnOffset(JmpSrc call) - { - ASSERT(call.m_offset >= 0); - return call.m_offset; - } - - // Linking & patching: - // - // 'link' and 'patch' methods are for use on unprotected code - such as the code - // within the AssemblerBuffer, and code being patched by the patch buffer. Once - // code has been finalized it is (platform support permitting) within a non- - // writable region of memory; to modify the code in an execute-only execuable - // pool the 'repatch' and 'relink' methods should be used. - - void linkJump(JmpSrc from, JmpDst to) - { - ASSERT(to.m_offset != -1); - ASSERT(from.m_offset != -1); - m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset, from.m_type, from.m_condition)); - } - - static void linkJump(void* code, JmpSrc from, void* to) - { - ASSERT(from.m_offset != -1); - - uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset); - linkJumpAbsolute(location, to); - } - - // bah, this mathod should really be static, since it is used by the LinkBuffer. - // return a bool saying whether the link was successful? - static void linkCall(void* code, JmpSrc from, void* to) - { - ASSERT(!(reinterpret_cast<intptr_t>(code) & 1)); - ASSERT(from.m_offset != -1); - ASSERT(reinterpret_cast<intptr_t>(to) & 1); - - setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to); - } - - static void linkPointer(void* code, JmpDst where, void* value) - { - setPointer(reinterpret_cast<char*>(code) + where.m_offset, value); - } - - static void relinkJump(void* from, void* to) - { - ASSERT(!(reinterpret_cast<intptr_t>(from) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(to) & 1)); - - linkJumpAbsolute(reinterpret_cast<uint16_t*>(from), to); - - ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 5 * sizeof(uint16_t)); - } - - static void relinkCall(void* from, void* to) - { - ASSERT(!(reinterpret_cast<intptr_t>(from) & 1)); - ASSERT(reinterpret_cast<intptr_t>(to) & 1); - - setPointer(reinterpret_cast<uint16_t*>(from) - 1, to); - } - - static void repatchInt32(void* where, int32_t value) - { - ASSERT(!(reinterpret_cast<intptr_t>(where) & 1)); - - setInt32(where, value); - } - - static void repatchPointer(void* where, void* value) - { - ASSERT(!(reinterpret_cast<intptr_t>(where) & 1)); - - setPointer(where, value); - } - - static void repatchLoadPtrToLEA(void* where) - { - ASSERT(!(reinterpret_cast<intptr_t>(where) & 1)); - uint16_t* loadOp = reinterpret_cast<uint16_t*>(where) + 4; - - ASSERT((loadOp[0] & 0xfff0) == OP_LDR_reg_T2); - ASSERT((loadOp[1] & 0x0ff0) == 0); - int rn = loadOp[0] & 0xf; - int rt = loadOp[1] >> 12; - int rm = loadOp[1] & 0xf; - - loadOp[0] = OP_ADD_reg_T3 | rn; - loadOp[1] = rt << 8 | rm; - ExecutableAllocator::cacheFlush(loadOp, sizeof(uint32_t)); - } - -private: - // VFP operations commonly take one or more 5-bit operands, typically representing a - // floating point register number. This will commonly be encoded in the instruction - // in two parts, with one single bit field, and one 4-bit field. In the case of - // double precision operands the high bit of the register number will be encoded - // separately, and for single precision operands the high bit of the register number - // will be encoded individually. - // VFPOperand encapsulates a 5-bit VFP operand, with bits 0..3 containing the 4-bit - // field to be encoded together in the instruction (the low 4-bits of a double - // register number, or the high 4-bits of a single register number), and bit 4 - // contains the bit value to be encoded individually. - struct VFPOperand { - explicit VFPOperand(uint32_t value) - : m_value(value) - { - ASSERT(!(m_value & ~0x1f)); - } - - VFPOperand(FPDoubleRegisterID reg) - : m_value(reg) - { - } - - VFPOperand(RegisterID reg) - : m_value(reg) - { - } - - VFPOperand(FPSingleRegisterID reg) - : m_value(((reg & 1) << 4) | (reg >> 1)) // rotate the lowest bit of 'reg' to the top. - { - } - - uint32_t bits1() - { - return m_value >> 4; - } - - uint32_t bits4() - { - return m_value & 0xf; - } - - uint32_t m_value; - }; - - VFPOperand vcvtOp(bool toInteger, bool isUnsigned, bool isRoundZero) - { - // Cannot specify rounding when converting to float. - ASSERT(toInteger || !isRoundZero); - - uint32_t op = 0x8; - if (toInteger) { - // opc2 indicates both toInteger & isUnsigned. - op |= isUnsigned ? 0x4 : 0x5; - // 'op' field in instruction is isRoundZero - if (isRoundZero) - op |= 0x10; - } else { - // 'op' field in instruction is isUnsigned - if (!isUnsigned) - op |= 0x10; - } - return VFPOperand(op); - } - - static void setInt32(void* code, uint32_t value) - { - uint16_t* location = reinterpret_cast<uint16_t*>(code); - ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2)); - - ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value)); - ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value >> 16)); - location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); - location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16); - location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); - location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16); - - ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t)); - } - - static void setPointer(void* code, void* value) - { - setInt32(code, reinterpret_cast<uint32_t>(value)); - } - - static bool isB(void* address) - { - uint16_t* instruction = static_cast<uint16_t*>(address); - return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b); - } - - static bool isBX(void* address) - { - uint16_t* instruction = static_cast<uint16_t*>(address); - return (instruction[0] & 0xff87) == OP_BX; - } - - static bool isMOV_imm_T3(void* address) - { - uint16_t* instruction = static_cast<uint16_t*>(address); - return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0); - } - - static bool isMOVT(void* address) - { - uint16_t* instruction = static_cast<uint16_t*>(address); - return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0); - } - - static bool isNOP_T1(void* address) - { - uint16_t* instruction = static_cast<uint16_t*>(address); - return instruction[0] == OP_NOP_T1; - } - - static bool isNOP_T2(void* address) - { - uint16_t* instruction = static_cast<uint16_t*>(address); - return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b); - } - - static bool canBeJumpT1(const uint16_t* instruction, const void* target) - { - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - - intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); - // It does not appear to be documented in the ARM ARM (big surprise), but - // for OP_B_T1 the branch displacement encoded in the instruction is 2 - // less than the actual displacement. - relative -= 2; - return ((relative << 23) >> 23) == relative; - } - - static bool canBeJumpT2(const uint16_t* instruction, const void* target) - { - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - - intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); - // It does not appear to be documented in the ARM ARM (big surprise), but - // for OP_B_T2 the branch displacement encoded in the instruction is 2 - // less than the actual displacement. - relative -= 2; - return ((relative << 20) >> 20) == relative; - } - - static bool canBeJumpT3(const uint16_t* instruction, const void* target, bool& mayTriggerErrata) - { - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - - intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); - // From Cortex-A8 errata: - // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and - // the target of the branch falls within the first region it is - // possible for the processor to incorrectly determine the branch - // instruction, and it is also possible in some cases for the processor - // to enter a deadlock state. - // The instruction is spanning two pages if it ends at an address ending 0x002 - bool spansTwo4K = ((reinterpret_cast<intptr_t>(instruction) & 0xfff) == 0x002); - mayTriggerErrata = spansTwo4K; - // The target is in the first page if the jump branch back by [3..0x1002] bytes - bool targetInFirstPage = (relative >= -0x1002) && (relative < -2); - bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage; - return ((relative << 11) >> 11) == relative && !wouldTriggerA8Errata; - } - - static bool canBeJumpT4(const uint16_t* instruction, const void* target, bool& mayTriggerErrata) - { - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - - intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); - // From Cortex-A8 errata: - // If the 32-bit Thumb-2 branch instruction spans two 4KiB regions and - // the target of the branch falls within the first region it is - // possible for the processor to incorrectly determine the branch - // instruction, and it is also possible in some cases for the processor - // to enter a deadlock state. - // The instruction is spanning two pages if it ends at an address ending 0x002 - bool spansTwo4K = ((reinterpret_cast<intptr_t>(instruction) & 0xfff) == 0x002); - mayTriggerErrata = spansTwo4K; - // The target is in the first page if the jump branch back by [3..0x1002] bytes - bool targetInFirstPage = (relative >= -0x1002) && (relative < -2); - bool wouldTriggerA8Errata = spansTwo4K && targetInFirstPage; - return ((relative << 7) >> 7) == relative && !wouldTriggerA8Errata; - } - - void linkJumpT1(Condition cond, uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - ASSERT(canBeJumpT1(instruction, target)); - - intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); - // It does not appear to be documented in the ARM ARM (big surprise), but - // for OP_B_T1 the branch displacement encoded in the instruction is 2 - // less than the actual displacement. - relative -= 2; - - // All branch offsets should be an even distance. - ASSERT(!(relative & 1)); - instruction[-1] = OP_B_T1 | ((cond & 0xf) << 8) | ((relative & 0x1fe) >> 1); - } - - static void linkJumpT2(uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - ASSERT(canBeJumpT2(instruction, target)); - - intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); - // It does not appear to be documented in the ARM ARM (big surprise), but - // for OP_B_T2 the branch displacement encoded in the instruction is 2 - // less than the actual displacement. - relative -= 2; - - // All branch offsets should be an even distance. - ASSERT(!(relative & 1)); - instruction[-1] = OP_B_T2 | ((relative & 0xffe) >> 1); - } - - void linkJumpT3(Condition cond, uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - bool scratch; - UNUSED_PARAM(scratch); - ASSERT(canBeJumpT3(instruction, target, scratch)); - - intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); - - // All branch offsets should be an even distance. - ASSERT(!(relative & 1)); - instruction[-2] = OP_B_T3a | ((relative & 0x100000) >> 10) | ((cond & 0xf) << 6) | ((relative & 0x3f000) >> 12); - instruction[-1] = OP_B_T3b | ((relative & 0x80000) >> 8) | ((relative & 0x40000) >> 5) | ((relative & 0xffe) >> 1); - } - - static void linkJumpT4(uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - bool scratch; - UNUSED_PARAM(scratch); - ASSERT(canBeJumpT4(instruction, target, scratch)); - - intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); - // ARM encoding for the top two bits below the sign bit is 'peculiar'. - if (relative >= 0) - relative ^= 0xC00000; - - // All branch offsets should be an even distance. - ASSERT(!(relative & 1)); - instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12); - instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1); - } - - void linkConditionalJumpT4(Condition cond, uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - - instruction[-3] = ifThenElse(cond) | OP_IT; - linkJumpT4(instruction, target); - } - - static void linkBX(uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - - const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip; - ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1)); - ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16)); - instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); - instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16); - instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); - instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16); - instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3); - } - - void linkConditionalBX(Condition cond, uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - - linkBX(instruction, target); - instruction[-6] = ifThenElse(cond, true, true) | OP_IT; - } - - static void linkJumpAbsolute(uint16_t* instruction, void* target) - { - // FIMXE: this should be up in the MacroAssembler layer. :-( - ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); - ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); - - ASSERT((isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1)) - || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2))); - - bool scratch; - if (canBeJumpT4(instruction, target, scratch)) { - // There may be a better way to fix this, but right now put the NOPs first, since in the - // case of an conditional branch this will be coming after an ITTT predicating *three* - // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to - // variable wdith encoding - the previous instruction might *look* like an ITTT but - // actually be the second half of a 2-word op. - instruction[-5] = OP_NOP_T1; - instruction[-4] = OP_NOP_T2a; - instruction[-3] = OP_NOP_T2b; - linkJumpT4(instruction, target); - } else { - const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip; - ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1)); - ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16)); - instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); - instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16); - instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); - instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16); - instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3); - } - } - - static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm) - { - return op | (imm.m_value.i << 10) | imm.m_value.imm4; - } - - static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm) - { - return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8; - } - - class ARMInstructionFormatter { - public: - void oneWordOp5Reg3Imm8(OpcodeID op, RegisterID rd, uint8_t imm) - { - m_buffer.putShort(op | (rd << 8) | imm); - } - - void oneWordOp5Imm5Reg3Reg3(OpcodeID op, uint8_t imm, RegisterID reg1, RegisterID reg2) - { - m_buffer.putShort(op | (imm << 6) | (reg1 << 3) | reg2); - } - - void oneWordOp7Reg3Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2, RegisterID reg3) - { - m_buffer.putShort(op | (reg1 << 6) | (reg2 << 3) | reg3); - } - - void oneWordOp8Imm8(OpcodeID op, uint8_t imm) - { - m_buffer.putShort(op | imm); - } - - void oneWordOp8RegReg143(OpcodeID op, RegisterID reg1, RegisterID reg2) - { - m_buffer.putShort(op | ((reg2 & 8) << 4) | (reg1 << 3) | (reg2 & 7)); - } - void oneWordOp9Imm7(OpcodeID op, uint8_t imm) - { - m_buffer.putShort(op | imm); - } - - void oneWordOp10Reg3Reg3(OpcodeID op, RegisterID reg1, RegisterID reg2) - { - m_buffer.putShort(op | (reg1 << 3) | reg2); - } - - void twoWordOp12Reg4FourFours(OpcodeID1 op, RegisterID reg, FourFours ff) - { - m_buffer.putShort(op | reg); - m_buffer.putShort(ff.m_u.value); - } - - void twoWordOp16FourFours(OpcodeID1 op, FourFours ff) - { - m_buffer.putShort(op); - m_buffer.putShort(ff.m_u.value); - } - - void twoWordOp16Op16(OpcodeID1 op1, OpcodeID2 op2) - { - m_buffer.putShort(op1); - m_buffer.putShort(op2); - } - - void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm) - { - ARMThumbImmediate newImm = imm; - newImm.m_value.imm4 = imm4; - - m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm)); - m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm)); - } - - void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm) - { - m_buffer.putShort(op | reg1); - m_buffer.putShort((reg2 << 12) | imm); - } - - // Formats up instructions of the pattern: - // 111111111B11aaaa:bbbb222SA2C2cccc - // Where 1s in the pattern come from op1, 2s in the pattern come from op2, S is the provided size bit. - // Operands provide 5 bit values of the form Aaaaa, Bbbbb, Ccccc. - void vfpOp(OpcodeID1 op1, OpcodeID2 op2, bool size, VFPOperand a, VFPOperand b, VFPOperand c) - { - ASSERT(!(op1 & 0x004f)); - ASSERT(!(op2 & 0xf1af)); - m_buffer.putShort(op1 | b.bits1() << 6 | a.bits4()); - m_buffer.putShort(op2 | b.bits4() << 12 | size << 8 | a.bits1() << 7 | c.bits1() << 5 | c.bits4()); - } - - // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. - // (i.e. +/-(0..255) 32-bit words) - void vfpMemOp(OpcodeID1 op1, OpcodeID2 op2, bool size, RegisterID rn, VFPOperand rd, int32_t imm) - { - bool up = true; - if (imm < 0) { - imm = -imm; - up = false; - } - - uint32_t offset = imm; - ASSERT(!(offset & ~0x3fc)); - offset >>= 2; - - m_buffer.putShort(op1 | (up << 7) | rd.bits1() << 6 | rn); - m_buffer.putShort(op2 | rd.bits4() << 12 | size << 8 | offset); - } - - // Administrative methods: - - size_t size() const { return m_buffer.size(); } - bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } - void* data() const { return m_buffer.data(); } - void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); } - - private: - AssemblerBuffer m_buffer; - } m_formatter; - - Vector<LinkRecord> m_jumpsToLink; - Vector<int32_t> m_offsets; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(ARM_THUMB2) - -#endif // ARMAssembler_h diff --git a/JavaScriptCore/assembler/AbstractMacroAssembler.h b/JavaScriptCore/assembler/AbstractMacroAssembler.h deleted file mode 100644 index 07bd702..0000000 --- a/JavaScriptCore/assembler/AbstractMacroAssembler.h +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef AbstractMacroAssembler_h -#define AbstractMacroAssembler_h - -#include "CodeLocation.h" -#include "MacroAssemblerCodeRef.h" -#include <wtf/Noncopyable.h> -#include <wtf/UnusedParam.h> - -#if ENABLE(ASSEMBLER) - -namespace JSC { - -class LinkBuffer; -class RepatchBuffer; - -template <class AssemblerType> -class AbstractMacroAssembler { -public: - typedef AssemblerType AssemblerType_T; - - typedef MacroAssemblerCodePtr CodePtr; - typedef MacroAssemblerCodeRef CodeRef; - - class Jump; - - typedef typename AssemblerType::RegisterID RegisterID; - typedef typename AssemblerType::JmpSrc JmpSrc; - typedef typename AssemblerType::JmpDst JmpDst; - - - // Section 1: MacroAssembler operand types - // - // The following types are used as operands to MacroAssembler operations, - // describing immediate and memory operands to the instructions to be planted. - - - enum Scale { - TimesOne, - TimesTwo, - TimesFour, - TimesEight, - }; - - // Address: - // - // Describes a simple base-offset address. - struct Address { - explicit Address(RegisterID base, int32_t offset = 0) - : base(base) - , offset(offset) - { - } - - RegisterID base; - int32_t offset; - }; - - struct ExtendedAddress { - explicit ExtendedAddress(RegisterID base, intptr_t offset = 0) - : base(base) - , offset(offset) - { - } - - RegisterID base; - intptr_t offset; - }; - - // ImplicitAddress: - // - // This class is used for explicit 'load' and 'store' operations - // (as opposed to situations in which a memory operand is provided - // to a generic operation, such as an integer arithmetic instruction). - // - // In the case of a load (or store) operation we want to permit - // addresses to be implicitly constructed, e.g. the two calls: - // - // load32(Address(addrReg), destReg); - // load32(addrReg, destReg); - // - // Are equivalent, and the explicit wrapping of the Address in the former - // is unnecessary. - struct ImplicitAddress { - ImplicitAddress(RegisterID base) - : base(base) - , offset(0) - { - } - - ImplicitAddress(Address address) - : base(address.base) - , offset(address.offset) - { - } - - RegisterID base; - int32_t offset; - }; - - // BaseIndex: - // - // Describes a complex addressing mode. - struct BaseIndex { - BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0) - : base(base) - , index(index) - , scale(scale) - , offset(offset) - { - } - - RegisterID base; - RegisterID index; - Scale scale; - int32_t offset; - }; - - // AbsoluteAddress: - // - // Describes an memory operand given by a pointer. For regular load & store - // operations an unwrapped void* will be used, rather than using this. - struct AbsoluteAddress { - explicit AbsoluteAddress(void* ptr) - : m_ptr(ptr) - { - } - - void* m_ptr; - }; - - // ImmPtr: - // - // A pointer sized immediate operand to an instruction - this is wrapped - // in a class requiring explicit construction in order to differentiate - // from pointers used as absolute addresses to memory operations - struct ImmPtr { - explicit ImmPtr(const void* value) - : m_value(value) - { - } - - intptr_t asIntptr() - { - return reinterpret_cast<intptr_t>(m_value); - } - - const void* m_value; - }; - - // Imm32: - // - // A 32bit immediate operand to an instruction - this is wrapped in a - // class requiring explicit construction in order to prevent RegisterIDs - // (which are implemented as an enum) from accidentally being passed as - // immediate values. - struct Imm32 { - explicit Imm32(int32_t value) - : m_value(value) -#if CPU(ARM) || CPU(MIPS) - , m_isPointer(false) -#endif - { - } - -#if !CPU(X86_64) - explicit Imm32(ImmPtr ptr) - : m_value(ptr.asIntptr()) -#if CPU(ARM) || CPU(MIPS) - , m_isPointer(true) -#endif - { - } -#endif - - int32_t m_value; -#if CPU(ARM) || CPU(MIPS) - // We rely on being able to regenerate code to recover exception handling - // information. Since ARMv7 supports 16-bit immediates there is a danger - // that if pointer values change the layout of the generated code will change. - // To avoid this problem, always generate pointers (and thus Imm32s constructed - // from ImmPtrs) with a code sequence that is able to represent any pointer - // value - don't use a more compact form in these cases. - // Same for MIPS. - bool m_isPointer; -#endif - }; - - - // Section 2: MacroAssembler code buffer handles - // - // The following types are used to reference items in the code buffer - // during JIT code generation. For example, the type Jump is used to - // track the location of a jump instruction so that it may later be - // linked to a label marking its destination. - - - // Label: - // - // A Label records a point in the generated instruction stream, typically such that - // it may be used as a destination for a jump. - class Label { - template<class TemplateAssemblerType> - friend class AbstractMacroAssembler; - friend class Jump; - friend class MacroAssemblerCodeRef; - friend class LinkBuffer; - - public: - Label() - { - } - - Label(AbstractMacroAssembler<AssemblerType>* masm) - : m_label(masm->m_assembler.label()) - { - } - - bool isUsed() const { return m_label.isUsed(); } - bool isSet() const { return m_label.isSet(); } - void used() { m_label.used(); } - private: - JmpDst m_label; - }; - - // DataLabelPtr: - // - // A DataLabelPtr is used to refer to a location in the code containing a pointer to be - // patched after the code has been generated. - class DataLabelPtr { - template<class TemplateAssemblerType> - friend class AbstractMacroAssembler; - friend class LinkBuffer; - public: - DataLabelPtr() - { - } - - DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm) - : m_label(masm->m_assembler.label()) - { - } - - bool isSet() const { return m_label.isSet(); } - - private: - JmpDst m_label; - }; - - // DataLabel32: - // - // A DataLabelPtr is used to refer to a location in the code containing a pointer to be - // patched after the code has been generated. - class DataLabel32 { - template<class TemplateAssemblerType> - friend class AbstractMacroAssembler; - friend class LinkBuffer; - public: - DataLabel32() - { - } - - DataLabel32(AbstractMacroAssembler<AssemblerType>* masm) - : m_label(masm->m_assembler.label()) - { - } - - private: - JmpDst m_label; - }; - - // Call: - // - // A Call object is a reference to a call instruction that has been planted - // into the code buffer - it is typically used to link the call, setting the - // relative offset such that when executed it will call to the desired - // destination. - class Call { - template<class TemplateAssemblerType> - friend class AbstractMacroAssembler; - - public: - enum Flags { - None = 0x0, - Linkable = 0x1, - Near = 0x2, - LinkableNear = 0x3, - }; - - Call() - : m_flags(None) - { - } - - Call(JmpSrc jmp, Flags flags) - : m_jmp(jmp) - , m_flags(flags) - { - } - - bool isFlagSet(Flags flag) - { - return m_flags & flag; - } - - static Call fromTailJump(Jump jump) - { - return Call(jump.m_jmp, Linkable); - } - - JmpSrc m_jmp; - private: - Flags m_flags; - }; - - // Jump: - // - // A jump object is a reference to a jump instruction that has been planted - // into the code buffer - it is typically used to link the jump, setting the - // relative offset such that when executed it will jump to the desired - // destination. - class Jump { - template<class TemplateAssemblerType> - friend class AbstractMacroAssembler; - friend class Call; - friend class LinkBuffer; - public: - Jump() - { - } - - Jump(JmpSrc jmp) - : m_jmp(jmp) - { - } - - void link(AbstractMacroAssembler<AssemblerType>* masm) - { - masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label()); - } - - void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) - { - masm->m_assembler.linkJump(m_jmp, label.m_label); - } - - private: - JmpSrc m_jmp; - }; - - // JumpList: - // - // A JumpList is a set of Jump objects. - // All jumps in the set will be linked to the same destination. - class JumpList { - friend class LinkBuffer; - - public: - typedef Vector<Jump, 16> JumpVector; - - void link(AbstractMacroAssembler<AssemblerType>* masm) - { - size_t size = m_jumps.size(); - for (size_t i = 0; i < size; ++i) - m_jumps[i].link(masm); - m_jumps.clear(); - } - - void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) - { - size_t size = m_jumps.size(); - for (size_t i = 0; i < size; ++i) - m_jumps[i].linkTo(label, masm); - m_jumps.clear(); - } - - void append(Jump jump) - { - m_jumps.append(jump); - } - - void append(JumpList& other) - { - m_jumps.append(other.m_jumps.begin(), other.m_jumps.size()); - } - - bool empty() - { - return !m_jumps.size(); - } - - void clear() - { - m_jumps.clear(); - } - - const JumpVector& jumps() { return m_jumps; } - - private: - JumpVector m_jumps; - }; - - - // Section 3: Misc admin methods - size_t size() - { - return m_assembler.size(); - } - - Label label() - { - return Label(this); - } - - Label align() - { - m_assembler.align(16); - return Label(this); - } - - ptrdiff_t differenceBetween(Label from, Jump to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); - } - - ptrdiff_t differenceBetween(Label from, Call to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); - } - - ptrdiff_t differenceBetween(Label from, Label to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(Label from, DataLabelPtr to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(Label from, DataLabel32 to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(DataLabelPtr from, Jump to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); - } - - ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label); - } - - ptrdiff_t differenceBetween(DataLabelPtr from, Call to) - { - return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp); - } - - void beginUninterruptedSequence() { } - void endUninterruptedSequence() { } - -protected: - AssemblerType m_assembler; - - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkJump(void* code, Jump jump, CodeLocationLabel target) - { - AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation()); - } - - static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value) - { - AssemblerType::linkPointer(code, label, value); - } - - static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label) - { - return AssemblerType::getRelocatedAddress(code, label); - } - - static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label) - { - return AssemblerType::getRelocatedAddress(code, label); - } - - static unsigned getLinkerCallReturnOffset(Call call) - { - return AssemblerType::getCallReturnOffset(call.m_jmp); - } - - static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination) - { - AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation()); - } - - static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination) - { - AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress()); - } - - static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value) - { - AssemblerType::repatchInt32(dataLabel32.dataLocation(), value); - } - - static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value) - { - AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value); - } - - static void repatchLoadPtrToLEA(CodeLocationInstruction instruction) - { - AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation()); - } -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // AbstractMacroAssembler_h diff --git a/JavaScriptCore/assembler/AssemblerBuffer.h b/JavaScriptCore/assembler/AssemblerBuffer.h deleted file mode 100644 index 0454a99..0000000 --- a/JavaScriptCore/assembler/AssemblerBuffer.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef AssemblerBuffer_h -#define AssemblerBuffer_h - -#if ENABLE(ASSEMBLER) - -#include "stdint.h" -#include <string.h> -#include <jit/ExecutableAllocator.h> -#include <wtf/Assertions.h> -#include <wtf/FastMalloc.h> -#include <wtf/StdLibExtras.h> - -namespace JSC { - - class AssemblerBuffer { - static const int inlineCapacity = 128 - sizeof(char*) - 2 * sizeof(int); - public: - AssemblerBuffer() - : m_buffer(m_inlineBuffer) - , m_capacity(inlineCapacity) - , m_size(0) - { - COMPILE_ASSERT(sizeof(AssemblerBuffer) == 128, AssemblerBuffer_should_be_128_bytes); - } - - ~AssemblerBuffer() - { - if (m_buffer != m_inlineBuffer) - fastFree(m_buffer); - } - - void ensureSpace(int space) - { - if (m_size > m_capacity - space) - grow(); - } - - bool isAligned(int alignment) const - { - return !(m_size & (alignment - 1)); - } - - void putByteUnchecked(int value) - { - ASSERT(!(m_size > m_capacity - 4)); - m_buffer[m_size] = value; - m_size++; - } - - void putByte(int value) - { - if (m_size > m_capacity - 4) - grow(); - putByteUnchecked(value); - } - - void putShortUnchecked(int value) - { - ASSERT(!(m_size > m_capacity - 4)); - *reinterpret_cast_ptr<short*>(&m_buffer[m_size]) = value; - m_size += 2; - } - - void putShort(int value) - { - if (m_size > m_capacity - 4) - grow(); - putShortUnchecked(value); - } - - void putIntUnchecked(int value) - { - ASSERT(!(m_size > m_capacity - 4)); - *reinterpret_cast_ptr<int*>(&m_buffer[m_size]) = value; - m_size += 4; - } - - void putInt64Unchecked(int64_t value) - { - ASSERT(!(m_size > m_capacity - 8)); - *reinterpret_cast_ptr<int64_t*>(&m_buffer[m_size]) = value; - m_size += 8; - } - - void putInt(int value) - { - if (m_size > m_capacity - 4) - grow(); - putIntUnchecked(value); - } - - void* data() const - { - return m_buffer; - } - - int size() const - { - return m_size; - } - - void* executableCopy(ExecutablePool* allocator) - { - if (!m_size) - return 0; - - void* result = allocator->alloc(m_size); - - if (!result) - return 0; - - ExecutableAllocator::makeWritable(result, m_size); - - return memcpy(result, m_buffer, m_size); - } - - protected: - void append(const char* data, int size) - { - if (m_size > m_capacity - size) - grow(size); - - memcpy(m_buffer + m_size, data, size); - m_size += size; - } - - void grow(int extraCapacity = 0) - { - m_capacity += m_capacity / 2 + extraCapacity; - - if (m_buffer == m_inlineBuffer) { - char* newBuffer = static_cast<char*>(fastMalloc(m_capacity)); - m_buffer = static_cast<char*>(memcpy(newBuffer, m_buffer, m_size)); - } else - m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_capacity)); - } - - char m_inlineBuffer[inlineCapacity]; - char* m_buffer; - int m_capacity; - int m_size; - }; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // AssemblerBuffer_h diff --git a/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h b/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h deleted file mode 100644 index 599be14..0000000 --- a/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (C) 2009 University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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. - */ - -#ifndef AssemblerBufferWithConstantPool_h -#define AssemblerBufferWithConstantPool_h - -#if ENABLE(ASSEMBLER) - -#include "AssemblerBuffer.h" -#include <wtf/SegmentedVector.h> - -#define ASSEMBLER_HAS_CONSTANT_POOL 1 - -namespace JSC { - -/* - On a constant pool 4 or 8 bytes data can be stored. The values can be - constants or addresses. The addresses should be 32 or 64 bits. The constants - should be double-precisions float or integer numbers which are hard to be - encoded as few machine instructions. - - TODO: The pool is desinged to handle both 32 and 64 bits values, but - currently only the 4 bytes constants are implemented and tested. - - The AssemblerBuffer can contain multiple constant pools. Each pool is inserted - into the instruction stream - protected by a jump instruction from the - execution flow. - - The flush mechanism is called when no space remain to insert the next instruction - into the pool. Three values are used to determine when the constant pool itself - have to be inserted into the instruction stream (Assembler Buffer): - - - maxPoolSize: size of the constant pool in bytes, this value cannot be - larger than the maximum offset of a PC relative memory load - - - barrierSize: size of jump instruction in bytes which protects the - constant pool from execution - - - maxInstructionSize: maximum length of a machine instruction in bytes - - There are some callbacks which solve the target architecture specific - address handling: - - - TYPE patchConstantPoolLoad(TYPE load, int value): - patch the 'load' instruction with the index of the constant in the - constant pool and return the patched instruction. - - - void patchConstantPoolLoad(void* loadAddr, void* constPoolAddr): - patch the a PC relative load instruction at 'loadAddr' address with the - final relative offset. The offset can be computed with help of - 'constPoolAddr' (the address of the constant pool) and index of the - constant (which is stored previously in the load instruction itself). - - - TYPE placeConstantPoolBarrier(int size): - return with a constant pool barrier instruction which jumps over the - constant pool. - - The 'put*WithConstant*' functions should be used to place a data into the - constant pool. -*/ - -template <int maxPoolSize, int barrierSize, int maxInstructionSize, class AssemblerType> -class AssemblerBufferWithConstantPool: public AssemblerBuffer { - typedef SegmentedVector<uint32_t, 512> LoadOffsets; -public: - enum { - UniqueConst, - ReusableConst, - UnusedEntry, - }; - - AssemblerBufferWithConstantPool() - : AssemblerBuffer() - , m_numConsts(0) - , m_maxDistance(maxPoolSize) - , m_lastConstDelta(0) - { - m_pool = static_cast<uint32_t*>(fastMalloc(maxPoolSize)); - m_mask = static_cast<char*>(fastMalloc(maxPoolSize / sizeof(uint32_t))); - } - - ~AssemblerBufferWithConstantPool() - { - fastFree(m_mask); - fastFree(m_pool); - } - - void ensureSpace(int space) - { - flushIfNoSpaceFor(space); - AssemblerBuffer::ensureSpace(space); - } - - void ensureSpace(int insnSpace, int constSpace) - { - flushIfNoSpaceFor(insnSpace, constSpace); - AssemblerBuffer::ensureSpace(insnSpace); - } - - bool isAligned(int alignment) - { - flushIfNoSpaceFor(alignment); - return AssemblerBuffer::isAligned(alignment); - } - - void putByteUnchecked(int value) - { - AssemblerBuffer::putByteUnchecked(value); - correctDeltas(1); - } - - void putByte(int value) - { - flushIfNoSpaceFor(1); - AssemblerBuffer::putByte(value); - correctDeltas(1); - } - - void putShortUnchecked(int value) - { - AssemblerBuffer::putShortUnchecked(value); - correctDeltas(2); - } - - void putShort(int value) - { - flushIfNoSpaceFor(2); - AssemblerBuffer::putShort(value); - correctDeltas(2); - } - - void putIntUnchecked(int value) - { - AssemblerBuffer::putIntUnchecked(value); - correctDeltas(4); - } - - void putInt(int value) - { - flushIfNoSpaceFor(4); - AssemblerBuffer::putInt(value); - correctDeltas(4); - } - - void putInt64Unchecked(int64_t value) - { - AssemblerBuffer::putInt64Unchecked(value); - correctDeltas(8); - } - - int size() - { - flushIfNoSpaceFor(maxInstructionSize, sizeof(uint64_t)); - return AssemblerBuffer::size(); - } - - int uncheckedSize() - { - return AssemblerBuffer::size(); - } - - void* executableCopy(ExecutablePool* allocator) - { - flushConstantPool(false); - return AssemblerBuffer::executableCopy(allocator); - } - - void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false) - { - if (!m_numConsts) - m_maxDistance = maxPoolSize; - flushIfNoSpaceFor(4, 4); - - m_loadOffsets.append(AssemblerBuffer::size()); - if (isReusable) - for (int i = 0; i < m_numConsts; ++i) { - if (m_mask[i] == ReusableConst && m_pool[i] == constant) { - AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, i)); - correctDeltas(4); - return; - } - } - - m_pool[m_numConsts] = constant; - m_mask[m_numConsts] = static_cast<char>(isReusable ? ReusableConst : UniqueConst); - - AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, m_numConsts)); - ++m_numConsts; - - correctDeltas(4, 4); - } - - // This flushing mechanism can be called after any unconditional jumps. - void flushWithoutBarrier(bool isForced = false) - { - // Flush if constant pool is more than 60% full to avoid overuse of this function. - if (isForced || 5 * m_numConsts > 3 * maxPoolSize / sizeof(uint32_t)) - flushConstantPool(false); - } - - uint32_t* poolAddress() - { - return m_pool; - } - - int sizeOfConstantPool() - { - return m_numConsts; - } - -private: - void correctDeltas(int insnSize) - { - m_maxDistance -= insnSize; - m_lastConstDelta -= insnSize; - if (m_lastConstDelta < 0) - m_lastConstDelta = 0; - } - - void correctDeltas(int insnSize, int constSize) - { - correctDeltas(insnSize); - - m_maxDistance -= m_lastConstDelta; - m_lastConstDelta = constSize; - } - - void flushConstantPool(bool useBarrier = true) - { - if (m_numConsts == 0) - return; - int alignPool = (AssemblerBuffer::size() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1); - - if (alignPool) - alignPool = sizeof(uint64_t) - alignPool; - - // Callback to protect the constant pool from execution - if (useBarrier) - AssemblerBuffer::putInt(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool)); - - if (alignPool) { - if (alignPool & 1) - AssemblerBuffer::putByte(AssemblerType::padForAlign8); - if (alignPool & 2) - AssemblerBuffer::putShort(AssemblerType::padForAlign16); - if (alignPool & 4) - AssemblerBuffer::putInt(AssemblerType::padForAlign32); - } - - int constPoolOffset = AssemblerBuffer::size(); - append(reinterpret_cast<char*>(m_pool), m_numConsts * sizeof(uint32_t)); - - // Patch each PC relative load - for (LoadOffsets::Iterator iter = m_loadOffsets.begin(); iter != m_loadOffsets.end(); ++iter) { - void* loadAddr = reinterpret_cast<void*>(m_buffer + *iter); - AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast<void*>(m_buffer + constPoolOffset)); - } - - m_loadOffsets.clear(); - m_numConsts = 0; - } - - void flushIfNoSpaceFor(int nextInsnSize) - { - if (m_numConsts == 0) - return; - int lastConstDelta = m_lastConstDelta > nextInsnSize ? m_lastConstDelta - nextInsnSize : 0; - if ((m_maxDistance < nextInsnSize + lastConstDelta + barrierSize + (int)sizeof(uint32_t))) - flushConstantPool(); - } - - void flushIfNoSpaceFor(int nextInsnSize, int nextConstSize) - { - if (m_numConsts == 0) - return; - if ((m_maxDistance < nextInsnSize + m_lastConstDelta + nextConstSize + barrierSize + (int)sizeof(uint32_t)) || - (m_numConsts * sizeof(uint32_t) + nextConstSize >= maxPoolSize)) - flushConstantPool(); - } - - uint32_t* m_pool; - char* m_mask; - LoadOffsets m_loadOffsets; - - int m_numConsts; - int m_maxDistance; - int m_lastConstDelta; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // AssemblerBufferWithConstantPool_h diff --git a/JavaScriptCore/assembler/CodeLocation.h b/JavaScriptCore/assembler/CodeLocation.h deleted file mode 100644 index e29029b..0000000 --- a/JavaScriptCore/assembler/CodeLocation.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef CodeLocation_h -#define CodeLocation_h - -#include "MacroAssemblerCodeRef.h" - -#if ENABLE(ASSEMBLER) - -namespace JSC { - -class CodeLocationInstruction; -class CodeLocationLabel; -class CodeLocationJump; -class CodeLocationCall; -class CodeLocationNearCall; -class CodeLocationDataLabel32; -class CodeLocationDataLabelPtr; - -// The CodeLocation* types are all pretty much do-nothing wrappers around -// CodePtr (or MacroAssemblerCodePtr, to give it its full name). These -// classes only exist to provide type-safety when linking and patching code. -// -// The one new piece of functionallity introduced by these classes is the -// ability to create (or put another way, to re-discover) another CodeLocation -// at an offset from one you already know. When patching code to optimize it -// we often want to patch a number of instructions that are short, fixed -// offsets apart. To reduce memory overhead we will only retain a pointer to -// one of the instructions, and we will use the *AtOffset methods provided by -// CodeLocationCommon to find the other points in the code to modify. -class CodeLocationCommon : public MacroAssemblerCodePtr { -public: - CodeLocationInstruction instructionAtOffset(int offset); - CodeLocationLabel labelAtOffset(int offset); - CodeLocationJump jumpAtOffset(int offset); - CodeLocationCall callAtOffset(int offset); - CodeLocationNearCall nearCallAtOffset(int offset); - CodeLocationDataLabelPtr dataLabelPtrAtOffset(int offset); - CodeLocationDataLabel32 dataLabel32AtOffset(int offset); - -protected: - CodeLocationCommon() - { - } - - CodeLocationCommon(MacroAssemblerCodePtr location) - : MacroAssemblerCodePtr(location) - { - } -}; - -class CodeLocationInstruction : public CodeLocationCommon { -public: - CodeLocationInstruction() {} - explicit CodeLocationInstruction(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationInstruction(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationLabel : public CodeLocationCommon { -public: - CodeLocationLabel() {} - explicit CodeLocationLabel(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationLabel(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationJump : public CodeLocationCommon { -public: - CodeLocationJump() {} - explicit CodeLocationJump(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationJump(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationCall : public CodeLocationCommon { -public: - CodeLocationCall() {} - explicit CodeLocationCall(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationCall(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationNearCall : public CodeLocationCommon { -public: - CodeLocationNearCall() {} - explicit CodeLocationNearCall(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationNearCall(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationDataLabel32 : public CodeLocationCommon { -public: - CodeLocationDataLabel32() {} - explicit CodeLocationDataLabel32(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationDataLabel32(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -class CodeLocationDataLabelPtr : public CodeLocationCommon { -public: - CodeLocationDataLabelPtr() {} - explicit CodeLocationDataLabelPtr(MacroAssemblerCodePtr location) - : CodeLocationCommon(location) {} - explicit CodeLocationDataLabelPtr(void* location) - : CodeLocationCommon(MacroAssemblerCodePtr(location)) {} -}; - -inline CodeLocationInstruction CodeLocationCommon::instructionAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationInstruction(reinterpret_cast<char*>(dataLocation()) + offset); -} - -inline CodeLocationLabel CodeLocationCommon::labelAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationLabel(reinterpret_cast<char*>(dataLocation()) + offset); -} - -inline CodeLocationJump CodeLocationCommon::jumpAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationJump(reinterpret_cast<char*>(dataLocation()) + offset); -} - -inline CodeLocationCall CodeLocationCommon::callAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationCall(reinterpret_cast<char*>(dataLocation()) + offset); -} - -inline CodeLocationNearCall CodeLocationCommon::nearCallAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationNearCall(reinterpret_cast<char*>(dataLocation()) + offset); -} - -inline CodeLocationDataLabelPtr CodeLocationCommon::dataLabelPtrAtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationDataLabelPtr(reinterpret_cast<char*>(dataLocation()) + offset); -} - -inline CodeLocationDataLabel32 CodeLocationCommon::dataLabel32AtOffset(int offset) -{ - ASSERT_VALID_CODE_OFFSET(offset); - return CodeLocationDataLabel32(reinterpret_cast<char*>(dataLocation()) + offset); -} - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // CodeLocation_h diff --git a/JavaScriptCore/assembler/LinkBuffer.h b/JavaScriptCore/assembler/LinkBuffer.h deleted file mode 100644 index e38b9d4..0000000 --- a/JavaScriptCore/assembler/LinkBuffer.h +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef LinkBuffer_h -#define LinkBuffer_h - -#if ENABLE(ASSEMBLER) - -#define DUMP_LINK_STATISTICS 0 -#define DUMP_CODE 0 - -#include <MacroAssembler.h> -#include <wtf/Noncopyable.h> - -namespace JSC { - -// LinkBuffer: -// -// This class assists in linking code generated by the macro assembler, once code generation -// has been completed, and the code has been copied to is final location in memory. At this -// time pointers to labels within the code may be resolved, and relative offsets to external -// addresses may be fixed. -// -// Specifically: -// * Jump objects may be linked to external targets, -// * The address of Jump objects may taken, such that it can later be relinked. -// * The return address of a Call may be acquired. -// * The address of a Label pointing into the code may be resolved. -// * The value referenced by a DataLabel may be set. -// -class LinkBuffer : public Noncopyable { - typedef MacroAssemblerCodeRef CodeRef; - typedef MacroAssemblerCodePtr CodePtr; - typedef MacroAssembler::Label Label; - typedef MacroAssembler::Jump Jump; - typedef MacroAssembler::JumpList JumpList; - typedef MacroAssembler::Call Call; - typedef MacroAssembler::DataLabel32 DataLabel32; - typedef MacroAssembler::DataLabelPtr DataLabelPtr; - typedef MacroAssembler::JmpDst JmpDst; -#if ENABLE(BRANCH_COMPACTION) - typedef MacroAssembler::LinkRecord LinkRecord; - typedef MacroAssembler::JumpLinkType JumpLinkType; -#endif - -public: - // Note: Initialization sequence is significant, since executablePool is a PassRefPtr. - // First, executablePool is copied into m_executablePool, then the initialization of - // m_code uses m_executablePool, *not* executablePool, since this is no longer valid. - // The linkOffset parameter should only be non-null when recompiling for exception info - LinkBuffer(MacroAssembler* masm, PassRefPtr<ExecutablePool> executablePool, void* linkOffset) - : m_executablePool(executablePool) - , m_size(0) - , m_code(0) - , m_assembler(masm) -#ifndef NDEBUG - , m_completed(false) -#endif - { - linkCode(linkOffset); - } - - ~LinkBuffer() - { - ASSERT(m_completed); - } - - // These methods are used to link or set values at code generation time. - - void link(Call call, FunctionPtr function) - { - ASSERT(call.isFlagSet(Call::Linkable)); - call.m_jmp = applyOffset(call.m_jmp); - MacroAssembler::linkCall(code(), call, function); - } - - void link(Jump jump, CodeLocationLabel label) - { - jump.m_jmp = applyOffset(jump.m_jmp); - MacroAssembler::linkJump(code(), jump, label); - } - - void link(JumpList list, CodeLocationLabel label) - { - for (unsigned i = 0; i < list.m_jumps.size(); ++i) - link(list.m_jumps[i], label); - } - - void patch(DataLabelPtr label, void* value) - { - JmpDst target = applyOffset(label.m_label); - MacroAssembler::linkPointer(code(), target, value); - } - - void patch(DataLabelPtr label, CodeLocationLabel value) - { - JmpDst target = applyOffset(label.m_label); - MacroAssembler::linkPointer(code(), target, value.executableAddress()); - } - - // These methods are used to obtain handles to allow the code to be relinked / repatched later. - - CodeLocationCall locationOf(Call call) - { - ASSERT(call.isFlagSet(Call::Linkable)); - ASSERT(!call.isFlagSet(Call::Near)); - return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_jmp))); - } - - CodeLocationNearCall locationOfNearCall(Call call) - { - ASSERT(call.isFlagSet(Call::Linkable)); - ASSERT(call.isFlagSet(Call::Near)); - return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), applyOffset(call.m_jmp))); - } - - CodeLocationLabel locationOf(Label label) - { - return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); - } - - CodeLocationDataLabelPtr locationOf(DataLabelPtr label) - { - return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); - } - - CodeLocationDataLabel32 locationOf(DataLabel32 label) - { - return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), applyOffset(label.m_label))); - } - - // This method obtains the return address of the call, given as an offset from - // the start of the code. - unsigned returnAddressOffset(Call call) - { - call.m_jmp = applyOffset(call.m_jmp); - return MacroAssembler::getLinkerCallReturnOffset(call); - } - - // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called - // once to complete generation of the code. 'finalizeCode()' is suited to situations - // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is - // suited to adding to an existing allocation. - CodeRef finalizeCode() - { - performFinalization(); - - return CodeRef(m_code, m_executablePool, m_size); - } - - CodeLocationLabel finalizeCodeAddendum() - { - performFinalization(); - - return CodeLocationLabel(code()); - } - - CodePtr trampolineAt(Label label) - { - return CodePtr(MacroAssembler::AssemblerType_T::getRelocatedAddress(code(), applyOffset(label.m_label))); - } - -private: - template <typename T> T applyOffset(T src) - { -#if ENABLE(BRANCH_COMPACTION) - src.m_offset -= m_assembler->executableOffsetFor(src.m_offset); -#endif - return src; - } - - // Keep this private! - the underlying code should only be obtained externally via - // finalizeCode() or finalizeCodeAddendum(). - void* code() - { - return m_code; - } - - void linkCode(void* linkOffset) - { - UNUSED_PARAM(linkOffset); - ASSERT(!m_code); -#if !ENABLE(BRANCH_COMPACTION) - m_code = m_assembler->m_assembler.executableCopy(m_executablePool.get()); - m_size = m_assembler->size(); -#else - size_t initialSize = m_assembler->size(); - m_code = (uint8_t*)m_executablePool->alloc(initialSize); - if (!m_code) - return; - ExecutableAllocator::makeWritable(m_code, m_assembler->size()); - uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode(); - uint8_t* outData = reinterpret_cast<uint8_t*>(m_code); - const uint8_t* linkBase = linkOffset ? reinterpret_cast<uint8_t*>(linkOffset) : outData; - int readPtr = 0; - int writePtr = 0; - Vector<LinkRecord>& jumpsToLink = m_assembler->jumpsToLink(); - unsigned jumpCount = jumpsToLink.size(); - for (unsigned i = 0; i < jumpCount; ++i) { - int offset = readPtr - writePtr; - ASSERT(!(offset & 1)); - - // Copy the instructions from the last jump to the current one. - size_t regionSize = jumpsToLink[i].from() - readPtr; - memcpy(outData + writePtr, inData + readPtr, regionSize); - m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset); - readPtr += regionSize; - writePtr += regionSize; - - // Calculate absolute address of the jump target, in the case of backwards - // branches we need to be precise, forward branches we are pessimistic - const uint8_t* target; - if (jumpsToLink[i].to() >= jumpsToLink[i].from()) - target = linkBase + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far - else - target = linkBase + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); - - JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], linkBase + writePtr, target); - // Compact branch if we can... - if (m_assembler->canCompact(jumpsToLink[i].type())) { - // Step back in the write stream - int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType); - if (delta) { - writePtr -= delta; - m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr); - } - } - jumpsToLink[i].setFrom(writePtr); - } - // Copy everything after the last jump - memcpy(outData + writePtr, inData + readPtr, m_assembler->size() - readPtr); - m_assembler->recordLinkOffsets(readPtr, m_assembler->size(), readPtr - writePtr); - - // Actually link everything (don't link if we've be given a linkoffset as it's a - // waste of time: linkOffset is used for recompiling to get exception info) - if (!linkOffset) { - for (unsigned i = 0; i < jumpCount; ++i) { - uint8_t* location = outData + jumpsToLink[i].from(); - uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to()); - m_assembler->link(jumpsToLink[i], location, target); - } - } - - jumpsToLink.clear(); - m_size = writePtr + m_assembler->size() - readPtr; - m_executablePool->tryShrink(m_code, initialSize, m_size); - -#if DUMP_LINK_STATISTICS - dumpLinkStatistics(m_code, initialSize, m_size); -#endif -#if DUMP_CODE - dumpCode(m_code, m_size); -#endif -#endif - } - - void performFinalization() - { -#ifndef NDEBUG - ASSERT(!m_completed); - m_completed = true; -#endif - - ExecutableAllocator::makeExecutable(code(), m_size); - ExecutableAllocator::cacheFlush(code(), m_size); - } - -#if DUMP_LINK_STATISTICS - static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize) - { - static unsigned linkCount = 0; - static unsigned totalInitialSize = 0; - static unsigned totalFinalSize = 0; - linkCount++; - totalInitialSize += initialSize; - totalFinalSize += finalSize; - printf("link %p: orig %u, compact %u (delta %u, %.2f%%)\n", - code, static_cast<unsigned>(initialSize), static_cast<unsigned>(finalSize), - static_cast<unsigned>(initialSize - finalSize), - 100.0 * (initialSize - finalSize) / initialSize); - printf("\ttotal %u: orig %u, compact %u (delta %u, %.2f%%)\n", - linkCount, totalInitialSize, totalFinalSize, totalInitialSize - totalFinalSize, - 100.0 * (totalInitialSize - totalFinalSize) / totalInitialSize); - } -#endif - -#if DUMP_CODE - static void dumpCode(void* code, size_t size) - { -#if CPU(ARM_THUMB2) - // Dump the generated code in an asm file format that can be assembled and then disassembled - // for debugging purposes. For example, save this output as jit.s: - // gcc -arch armv7 -c jit.s - // otool -tv jit.o - static unsigned codeCount = 0; - unsigned short* tcode = static_cast<unsigned short*>(code); - size_t tsize = size / sizeof(short); - char nameBuf[128]; - snprintf(nameBuf, sizeof(nameBuf), "_jsc_jit%u", codeCount++); - printf("\t.syntax unified\n" - "\t.section\t__TEXT,__text,regular,pure_instructions\n" - "\t.globl\t%s\n" - "\t.align 2\n" - "\t.code 16\n" - "\t.thumb_func\t%s\n" - "# %p\n" - "%s:\n", nameBuf, nameBuf, code, nameBuf); - - for (unsigned i = 0; i < tsize; i++) - printf("\t.short\t0x%x\n", tcode[i]); -#endif - } -#endif - - RefPtr<ExecutablePool> m_executablePool; - size_t m_size; - void* m_code; - MacroAssembler* m_assembler; -#ifndef NDEBUG - bool m_completed; -#endif -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // LinkBuffer_h diff --git a/JavaScriptCore/assembler/MIPSAssembler.h b/JavaScriptCore/assembler/MIPSAssembler.h deleted file mode 100644 index f7bea6c..0000000 --- a/JavaScriptCore/assembler/MIPSAssembler.h +++ /dev/null @@ -1,984 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * Copyright (C) 2009 University of Szeged - * All rights reserved. - * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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. - */ - -#ifndef MIPSAssembler_h -#define MIPSAssembler_h - -#if ENABLE(ASSEMBLER) && CPU(MIPS) - -#include "AssemblerBuffer.h" -#include <wtf/Assertions.h> -#include <wtf/SegmentedVector.h> - -namespace JSC { - -typedef uint32_t MIPSWord; - -namespace MIPSRegisters { -typedef enum { - r0 = 0, - r1, - r2, - r3, - r4, - r5, - r6, - r7, - r8, - r9, - r10, - r11, - r12, - r13, - r14, - r15, - r16, - r17, - r18, - r19, - r20, - r21, - r22, - r23, - r24, - r25, - r26, - r27, - r28, - r29, - r30, - r31, - zero = r0, - at = r1, - v0 = r2, - v1 = r3, - a0 = r4, - a1 = r5, - a2 = r6, - a3 = r7, - t0 = r8, - t1 = r9, - t2 = r10, - t3 = r11, - t4 = r12, - t5 = r13, - t6 = r14, - t7 = r15, - s0 = r16, - s1 = r17, - s2 = r18, - s3 = r19, - s4 = r20, - s5 = r21, - s6 = r22, - s7 = r23, - t8 = r24, - t9 = r25, - k0 = r26, - k1 = r27, - gp = r28, - sp = r29, - fp = r30, - ra = r31 -} RegisterID; - -typedef enum { - f0, - f1, - f2, - f3, - f4, - f5, - f6, - f7, - f8, - f9, - f10, - f11, - f12, - f13, - f14, - f15, - f16, - f17, - f18, - f19, - f20, - f21, - f22, - f23, - f24, - f25, - f26, - f27, - f28, - f29, - f30, - f31 -} FPRegisterID; - -} // namespace MIPSRegisters - -class MIPSAssembler { -public: - typedef MIPSRegisters::RegisterID RegisterID; - typedef MIPSRegisters::FPRegisterID FPRegisterID; - typedef SegmentedVector<int, 64> Jumps; - - MIPSAssembler() - { - } - - // MIPS instruction opcode field position - enum { - OP_SH_RD = 11, - OP_SH_RT = 16, - OP_SH_RS = 21, - OP_SH_SHAMT = 6, - OP_SH_CODE = 16, - OP_SH_FD = 6, - OP_SH_FS = 11, - OP_SH_FT = 16 - }; - - class JmpSrc { - friend class MIPSAssembler; - public: - JmpSrc() - : m_offset(-1) - { - } - - private: - JmpSrc(int offset) - : m_offset(offset) - { - } - - int m_offset; - }; - - class JmpDst { - friend class MIPSAssembler; - public: - JmpDst() - : m_offset(-1) - , m_used(false) - { - } - - bool isUsed() const { return m_used; } - bool isSet() const { return (m_offset != -1); } - void used() { m_used = true; } - private: - JmpDst(int offset) - : m_offset(offset) - , m_used(false) - { - ASSERT(m_offset == offset); - } - - int m_offset : 31; - int m_used : 1; - }; - - void emitInst(MIPSWord op) - { - void* oldBase = m_buffer.data(); - - m_buffer.putInt(op); - - void* newBase = m_buffer.data(); - if (oldBase != newBase) - relocateJumps(oldBase, newBase); - } - - void nop() - { - emitInst(0x00000000); - } - - /* Need to insert one load data delay nop for mips1. */ - void loadDelayNop() - { -#if WTF_MIPS_ISA(1) - nop(); -#endif - } - - /* Need to insert one coprocessor access delay nop for mips1. */ - void copDelayNop() - { -#if WTF_MIPS_ISA(1) - nop(); -#endif - } - - void move(RegisterID rd, RegisterID rs) - { - /* addu */ - emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)); - } - - /* Set an immediate value to a register. This may generate 1 or 2 - instructions. */ - void li(RegisterID dest, int imm) - { - if (imm >= -32768 && imm <= 32767) - addiu(dest, MIPSRegisters::zero, imm); - else if (imm >= 0 && imm < 65536) - ori(dest, MIPSRegisters::zero, imm); - else { - lui(dest, imm >> 16); - if (imm & 0xffff) - ori(dest, dest, imm); - } - } - - void lui(RegisterID rt, int imm) - { - emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff)); - } - - void addiu(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void addu(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void subu(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void mult(RegisterID rs, RegisterID rt) - { - emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT)); - } - - void div(RegisterID rs, RegisterID rt) - { - emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT)); - } - - void mfhi(RegisterID rd) - { - emitInst(0x00000010 | (rd << OP_SH_RD)); - } - - void mflo(RegisterID rd) - { - emitInst(0x00000012 | (rd << OP_SH_RD)); - } - - void mul(RegisterID rd, RegisterID rs, RegisterID rt) - { -#if WTF_MIPS_ISA_AT_LEAST(32) - emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); -#else - mult(rs, rt); - mflo(rd); -#endif - } - - void andInsn(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void andi(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void nor(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void orInsn(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void ori(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void xori(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void slt(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void sltu(RegisterID rd, RegisterID rs, RegisterID rt) - { - emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS) - | (rt << OP_SH_RT)); - } - - void sltiu(RegisterID rt, RegisterID rs, int imm) - { - emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (imm & 0xffff)); - } - - void sll(RegisterID rd, RegisterID rt, int shamt) - { - emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | ((shamt & 0x1f) << OP_SH_SHAMT)); - } - - void sllv(RegisterID rd, RegisterID rt, int rs) - { - emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | (rs << OP_SH_RS)); - } - - void sra(RegisterID rd, RegisterID rt, int shamt) - { - emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | ((shamt & 0x1f) << OP_SH_SHAMT)); - } - - void srav(RegisterID rd, RegisterID rt, RegisterID rs) - { - emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | (rs << OP_SH_RS)); - } - - void srl(RegisterID rd, RegisterID rt, int shamt) - { - emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | ((shamt & 0x1f) << OP_SH_SHAMT)); - } - - void srlv(RegisterID rd, RegisterID rt, RegisterID rs) - { - emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT) - | (rs << OP_SH_RS)); - } - - void lbu(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lw(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lwl(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lwr(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void lhu(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - loadDelayNop(); - } - - void sw(RegisterID rt, RegisterID rs, int offset) - { - emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void jr(RegisterID rs) - { - emitInst(0x00000008 | (rs << OP_SH_RS)); - } - - void jalr(RegisterID rs) - { - emitInst(0x0000f809 | (rs << OP_SH_RS)); - } - - void jal() - { - emitInst(0x0c000000); - } - - void bkpt() - { - int value = 512; /* BRK_BUG */ - emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE)); - } - - void bgez(RegisterID rs, int imm) - { - emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff)); - } - - void bltz(RegisterID rs, int imm) - { - emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff)); - } - - void beq(RegisterID rs, RegisterID rt, int imm) - { - emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff)); - } - - void bne(RegisterID rs, RegisterID rt, int imm) - { - emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff)); - } - - void bc1t() - { - emitInst(0x45010000); - } - - void bc1f() - { - emitInst(0x45000000); - } - - JmpSrc newJmpSrc() - { - return JmpSrc(m_buffer.size()); - } - - void appendJump() - { - m_jumps.append(m_buffer.size()); - } - - void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS) - | (ft << OP_SH_FT)); - } - - void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS) - | (ft << OP_SH_FT)); - } - - void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS) - | (ft << OP_SH_FT)); - } - - void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS) - | (ft << OP_SH_FT)); - } - - void lwc1(FPRegisterID ft, RegisterID rs, int offset) - { - emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - copDelayNop(); - } - - void ldc1(FPRegisterID ft, RegisterID rs, int offset) - { - emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void swc1(FPRegisterID ft, RegisterID rs, int offset) - { - emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void sdc1(FPRegisterID ft, RegisterID rs, int offset) - { - emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) - | (offset & 0xffff)); - } - - void mtc1(RegisterID rt, FPRegisterID fs) - { - emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); - copDelayNop(); - } - - void mthc1(RegisterID rt, FPRegisterID fs) - { - emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); - copDelayNop(); - } - - void mfc1(RegisterID rt, FPRegisterID fs) - { - emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT)); - copDelayNop(); - } - - void sqrtd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void truncwd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void cvtdw(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void cvtwd(FPRegisterID fd, FPRegisterID fs) - { - emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS)); - } - - void ceqd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cngtd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cnged(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cltd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cled(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cueqd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void coled(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void coltd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void culed(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - void cultd(FPRegisterID fs, FPRegisterID ft) - { - emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT)); - copDelayNop(); - } - - // General helpers - - JmpDst label() - { - return JmpDst(m_buffer.size()); - } - - JmpDst align(int alignment) - { - while (!m_buffer.isAligned(alignment)) - bkpt(); - - return label(); - } - - static void* getRelocatedAddress(void* code, JmpSrc jump) - { - ASSERT(jump.m_offset != -1); - void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset); - return b; - } - - static void* getRelocatedAddress(void* code, JmpDst label) - { - void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset); - return b; - } - - static int getDifferenceBetweenLabels(JmpDst from, JmpDst to) - { - return to.m_offset - from.m_offset; - } - - static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to) - { - return to.m_offset - from.m_offset; - } - - static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to) - { - return to.m_offset - from.m_offset; - } - - // Assembler admin methods: - - size_t size() const - { - return m_buffer.size(); - } - - void* executableCopy(ExecutablePool* allocator) - { - void *result = m_buffer.executableCopy(allocator); - if (!result) - return 0; - - relocateJumps(m_buffer.data(), result); - return result; - } - - static unsigned getCallReturnOffset(JmpSrc call) - { - // The return address is after a call and a delay slot instruction - return call.m_offset; - } - - // Linking & patching: - // - // 'link' and 'patch' methods are for use on unprotected code - such as the code - // within the AssemblerBuffer, and code being patched by the patch buffer. Once - // code has been finalized it is (platform support permitting) within a non- - // writable region of memory; to modify the code in an execute-only execuable - // pool the 'repatch' and 'relink' methods should be used. - - void linkJump(JmpSrc from, JmpDst to) - { - ASSERT(to.m_offset != -1); - ASSERT(from.m_offset != -1); - MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset); - MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset); - - ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5))); - insn = insn - 6; - linkWithOffset(insn, toPos); - } - - static void linkJump(void* code, JmpSrc from, void* to) - { - ASSERT(from.m_offset != -1); - MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset); - - ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5))); - insn = insn - 6; - linkWithOffset(insn, to); - } - - static void linkCall(void* code, JmpSrc from, void* to) - { - MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset); - linkCallInternal(insn, to); - } - - static void linkPointer(void* code, JmpDst from, void* to) - { - MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset); - ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui - *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff); - insn++; - ASSERT((*insn & 0xfc000000) == 0x34000000); // ori - *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff); - } - - static void relinkJump(void* from, void* to) - { - MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); - - ASSERT(!(*(insn - 1)) && !(*(insn - 5))); - insn = insn - 6; - int flushSize = linkWithOffset(insn, to); - - ExecutableAllocator::cacheFlush(insn, flushSize); - } - - static void relinkCall(void* from, void* to) - { - void* start; - int size = linkCallInternal(from, to); - if (size == sizeof(MIPSWord)) - start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord)); - else - start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord)); - - ExecutableAllocator::cacheFlush(start, size); - } - - static void repatchInt32(void* from, int32_t to) - { - MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); - ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui - *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff); - insn++; - ASSERT((*insn & 0xfc000000) == 0x34000000); // ori - *insn = (*insn & 0xffff0000) | (to & 0xffff); - insn--; - ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord)); - } - - static void repatchPointer(void* from, void* to) - { - repatchInt32(from, reinterpret_cast<int32_t>(to)); - } - - static void repatchLoadPtrToLEA(void* from) - { - MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); - insn = insn + 3; - ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw - /* lw -> addiu */ - *insn = 0x24000000 | (*insn & 0x03ffffff); - - ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord)); - } - -private: - - /* Update each jump in the buffer of newBase. */ - void relocateJumps(void* oldBase, void* newBase) - { - // Check each jump - for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { - int pos = *iter; - MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos); - insn = insn + 2; - // Need to make sure we have 5 valid instructions after pos - if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord)) - continue; - - if ((*insn & 0xfc000000) == 0x08000000) { // j - int offset = *insn & 0x03ffffff; - int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase; - int topFourBits = (oldInsnAddress + 4) >> 28; - int oldTargetAddress = (topFourBits << 28) | (offset << 2); - int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase; - int newInsnAddress = (int)insn; - if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28)) - *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff); - else { - /* lui */ - *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); - /* ori */ - *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); - /* jr */ - *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS); - } - } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui - int high = (*insn & 0xffff) << 16; - int low = *(insn + 1) & 0xffff; - int oldTargetAddress = high | low; - int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase; - /* lui */ - *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); - /* ori */ - *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); - } - } - } - - static int linkWithOffset(MIPSWord* insn, void* to) - { - ASSERT((*insn & 0xfc000000) == 0x10000000 // beq - || (*insn & 0xfc000000) == 0x14000000 // bne - || (*insn & 0xffff0000) == 0x45010000 // bc1t - || (*insn & 0xffff0000) == 0x45000000); // bc1f - intptr_t diff = (reinterpret_cast<intptr_t>(to) - - reinterpret_cast<intptr_t>(insn) - 4) >> 2; - - if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) { - /* - Convert the sequence: - beq $2, $3, target - nop - b 1f - nop - nop - nop - 1: - - to the new sequence if possible: - bne $2, $3, 1f - nop - j target - nop - nop - nop - 1: - - OR to the new sequence: - bne $2, $3, 1f - nop - lui $25, target >> 16 - ori $25, $25, target & 0xffff - jr $25 - nop - 1: - - Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t. - */ - - if (*(insn + 2) == 0x10000003) { - if ((*insn & 0xfc000000) == 0x10000000) // beq - *insn = (*insn & 0x03ff0000) | 0x14000005; // bne - else if ((*insn & 0xfc000000) == 0x14000000) // bne - *insn = (*insn & 0x03ff0000) | 0x10000005; // beq - else if ((*insn & 0xffff0000) == 0x45010000) // bc1t - *insn = 0x45000005; // bc1f - else if ((*insn & 0xffff0000) == 0x45000000) // bc1f - *insn = 0x45010005; // bc1t - else - ASSERT(0); - } - - insn = insn + 2; - if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28 - == reinterpret_cast<intptr_t>(to) >> 28) { - *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff); - *(insn + 1) = 0; - return 4 * sizeof(MIPSWord); - } - - intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to); - /* lui */ - *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff); - /* ori */ - *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff); - /* jr */ - *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS); - return 5 * sizeof(MIPSWord); - } - - *insn = (*insn & 0xffff0000) | (diff & 0xffff); - return sizeof(MIPSWord); - } - - static int linkCallInternal(void* from, void* to) - { - MIPSWord* insn = reinterpret_cast<MIPSWord*>(from); - insn = insn - 4; - - if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal - if ((reinterpret_cast<intptr_t>(from) - 4) >> 28 - == reinterpret_cast<intptr_t>(to) >> 28) { - *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff); - return sizeof(MIPSWord); - } - - /* lui $25, (to >> 16) & 0xffff */ - *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff); - /* ori $25, $25, to & 0xffff */ - *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff); - /* jalr $25 */ - *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS); - return 3 * sizeof(MIPSWord); - } - - ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui - ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori - - /* lui */ - *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff); - /* ori */ - *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff); - return 2 * sizeof(MIPSWord); - } - - AssemblerBuffer m_buffer; - Jumps m_jumps; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(MIPS) - -#endif // MIPSAssembler_h diff --git a/JavaScriptCore/assembler/MacroAssembler.h b/JavaScriptCore/assembler/MacroAssembler.h deleted file mode 100644 index fa165de..0000000 --- a/JavaScriptCore/assembler/MacroAssembler.h +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef MacroAssembler_h -#define MacroAssembler_h - -#if ENABLE(ASSEMBLER) - -#if CPU(ARM_THUMB2) -#include "MacroAssemblerARMv7.h" -namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; }; - -#elif CPU(ARM_TRADITIONAL) -#include "MacroAssemblerARM.h" -namespace JSC { typedef MacroAssemblerARM MacroAssemblerBase; }; - -#elif CPU(MIPS) -#include "MacroAssemblerMIPS.h" -namespace JSC { -typedef MacroAssemblerMIPS MacroAssemblerBase; -}; - -#elif CPU(X86) -#include "MacroAssemblerX86.h" -namespace JSC { typedef MacroAssemblerX86 MacroAssemblerBase; }; - -#elif CPU(X86_64) -#include "MacroAssemblerX86_64.h" -namespace JSC { typedef MacroAssemblerX86_64 MacroAssemblerBase; }; - -#else -#error "The MacroAssembler is not supported on this platform." -#endif - - -namespace JSC { - -class MacroAssembler : public MacroAssemblerBase { -public: - - using MacroAssemblerBase::pop; - using MacroAssemblerBase::jump; - using MacroAssemblerBase::branch32; - using MacroAssemblerBase::branch16; -#if CPU(X86_64) - using MacroAssemblerBase::branchPtr; - using MacroAssemblerBase::branchTestPtr; -#endif - - - // Platform agnostic onvenience functions, - // described in terms of other macro assembly methods. - void pop() - { - addPtr(Imm32(sizeof(void*)), stackPointerRegister); - } - - void peek(RegisterID dest, int index = 0) - { - loadPtr(Address(stackPointerRegister, (index * sizeof(void*))), dest); - } - - void poke(RegisterID src, int index = 0) - { - storePtr(src, Address(stackPointerRegister, (index * sizeof(void*)))); - } - - void poke(Imm32 value, int index = 0) - { - store32(value, Address(stackPointerRegister, (index * sizeof(void*)))); - } - - void poke(ImmPtr imm, int index = 0) - { - storePtr(imm, Address(stackPointerRegister, (index * sizeof(void*)))); - } - - - // Backwards banches, these are currently all implemented using existing forwards branch mechanisms. - void branchPtr(Condition cond, RegisterID op1, ImmPtr imm, Label target) - { - branchPtr(cond, op1, imm).linkTo(target, this); - } - - void branch32(Condition cond, RegisterID op1, RegisterID op2, Label target) - { - branch32(cond, op1, op2).linkTo(target, this); - } - - void branch32(Condition cond, RegisterID op1, Imm32 imm, Label target) - { - branch32(cond, op1, imm).linkTo(target, this); - } - - void branch32(Condition cond, RegisterID left, Address right, Label target) - { - branch32(cond, left, right).linkTo(target, this); - } - - void branch16(Condition cond, BaseIndex left, RegisterID right, Label target) - { - branch16(cond, left, right).linkTo(target, this); - } - - void branchTestPtr(Condition cond, RegisterID reg, Label target) - { - branchTestPtr(cond, reg).linkTo(target, this); - } - - void jump(Label target) - { - jump().linkTo(target, this); - } - - - // Ptr methods - // On 32-bit platforms (i.e. x86), these methods directly map onto their 32-bit equivalents. - // FIXME: should this use a test for 32-bitness instead of this specific exception? -#if !CPU(X86_64) - void addPtr(RegisterID src, RegisterID dest) - { - add32(src, dest); - } - - void addPtr(Imm32 imm, RegisterID srcDest) - { - add32(imm, srcDest); - } - - void addPtr(ImmPtr imm, RegisterID dest) - { - add32(Imm32(imm), dest); - } - - void addPtr(Imm32 imm, RegisterID src, RegisterID dest) - { - add32(imm, src, dest); - } - - void andPtr(RegisterID src, RegisterID dest) - { - and32(src, dest); - } - - void andPtr(Imm32 imm, RegisterID srcDest) - { - and32(imm, srcDest); - } - - void orPtr(RegisterID src, RegisterID dest) - { - or32(src, dest); - } - - void orPtr(ImmPtr imm, RegisterID dest) - { - or32(Imm32(imm), dest); - } - - void orPtr(Imm32 imm, RegisterID dest) - { - or32(imm, dest); - } - - void subPtr(RegisterID src, RegisterID dest) - { - sub32(src, dest); - } - - void subPtr(Imm32 imm, RegisterID dest) - { - sub32(imm, dest); - } - - void subPtr(ImmPtr imm, RegisterID dest) - { - sub32(Imm32(imm), dest); - } - - void xorPtr(RegisterID src, RegisterID dest) - { - xor32(src, dest); - } - - void xorPtr(Imm32 imm, RegisterID srcDest) - { - xor32(imm, srcDest); - } - - - void loadPtr(ImplicitAddress address, RegisterID dest) - { - load32(address, dest); - } - - void loadPtr(BaseIndex address, RegisterID dest) - { - load32(address, dest); - } - - void loadPtr(void* address, RegisterID dest) - { - load32(address, dest); - } - - DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest) - { - return load32WithAddressOffsetPatch(address, dest); - } - - void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - set32Compare32(cond, left, right, dest); - } - - void storePtr(RegisterID src, ImplicitAddress address) - { - store32(src, address); - } - - void storePtr(RegisterID src, BaseIndex address) - { - store32(src, address); - } - - void storePtr(RegisterID src, void* address) - { - store32(src, address); - } - - void storePtr(ImmPtr imm, ImplicitAddress address) - { - store32(Imm32(imm), address); - } - - void storePtr(ImmPtr imm, void* address) - { - store32(Imm32(imm), address); - } - - DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address) - { - return store32WithAddressOffsetPatch(src, address); - } - - - Jump branchPtr(Condition cond, RegisterID left, RegisterID right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, RegisterID left, ImmPtr right) - { - return branch32(cond, left, Imm32(right)); - } - - Jump branchPtr(Condition cond, RegisterID left, Address right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, Address left, RegisterID right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right) - { - return branch32(cond, left, right); - } - - Jump branchPtr(Condition cond, Address left, ImmPtr right) - { - return branch32(cond, left, Imm32(right)); - } - - Jump branchPtr(Condition cond, AbsoluteAddress left, ImmPtr right) - { - return branch32(cond, left, Imm32(right)); - } - - Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask) - { - return branchTest32(cond, reg, mask); - } - - Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - return branchTest32(cond, reg, mask); - } - - Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - return branchTest32(cond, address, mask); - } - - Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - return branchTest32(cond, address, mask); - } - - - Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest) - { - return branchAdd32(cond, src, dest); - } - - Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest) - { - return branchSub32(cond, imm, dest); - } - using MacroAssemblerBase::branchTest8; - Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1)) - { - return MacroAssemblerBase::branchTest8(cond, Address(address.base, address.offset), mask); - } -#endif - -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // MacroAssembler_h diff --git a/JavaScriptCore/assembler/MacroAssemblerARM.cpp b/JavaScriptCore/assembler/MacroAssemblerARM.cpp deleted file mode 100644 index 2db5df1..0000000 --- a/JavaScriptCore/assembler/MacroAssemblerARM.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2009 University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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 "config.h" - -#if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) - -#include "MacroAssemblerARM.h" - -#if OS(LINUX) -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <elf.h> -#include <asm/hwcap.h> -#endif - -namespace JSC { - -static bool isVFPPresent() -{ -#if OS(LINUX) - int fd = open("/proc/self/auxv", O_RDONLY); - if (fd > 0) { - Elf32_auxv_t aux; - while (read(fd, &aux, sizeof(Elf32_auxv_t))) { - if (aux.a_type == AT_HWCAP) { - close(fd); - return aux.a_un.a_val & HWCAP_VFP; - } - } - close(fd); - } -#endif - -#if (COMPILER(RVCT) && defined(__TARGET_FPU_VFP)) || (COMPILER(GCC) && defined(__VFP_FP__)) - return true; -#else - return false; -#endif -} - -const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent(); - -#if CPU(ARMV5_OR_LOWER) -/* On ARMv5 and below, natural alignment is required. */ -void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) -{ - ARMWord op2; - - ASSERT(address.scale >= 0 && address.scale <= 3); - op2 = m_assembler.lsl(address.index, static_cast<int>(address.scale)); - - if (address.offset >= 0 && address.offset + 0x2 <= 0xff) { - m_assembler.add_r(ARMRegisters::S0, address.base, op2); - m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset)); - m_assembler.ldrh_u(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset + 0x2)); - } else if (address.offset < 0 && address.offset >= -0xff) { - m_assembler.add_r(ARMRegisters::S0, address.base, op2); - m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset)); - m_assembler.ldrh_d(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset - 0x2)); - } else { - m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, op2); - m_assembler.ldrh_r(dest, address.base, ARMRegisters::S0); - m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::OP2_IMM | 0x2); - m_assembler.ldrh_r(ARMRegisters::S0, address.base, ARMRegisters::S0); - } - m_assembler.orr_r(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16)); -} -#endif - -} - -#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) diff --git a/JavaScriptCore/assembler/MacroAssemblerARM.h b/JavaScriptCore/assembler/MacroAssemblerARM.h deleted file mode 100644 index 73390f8..0000000 --- a/JavaScriptCore/assembler/MacroAssemblerARM.h +++ /dev/null @@ -1,1036 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. - * Copyright (C) 2009, 2010 University of Szeged - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef MacroAssemblerARM_h -#define MacroAssemblerARM_h - -#if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) - -#include "ARMAssembler.h" -#include "AbstractMacroAssembler.h" - -namespace JSC { - -class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> { - static const int DoubleConditionMask = 0x0f; - static const int DoubleConditionBitSpecial = 0x10; - COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes); -public: - typedef ARMRegisters::FPRegisterID FPRegisterID; - - enum Condition { - Equal = ARMAssembler::EQ, - NotEqual = ARMAssembler::NE, - Above = ARMAssembler::HI, - AboveOrEqual = ARMAssembler::CS, - Below = ARMAssembler::CC, - BelowOrEqual = ARMAssembler::LS, - GreaterThan = ARMAssembler::GT, - GreaterThanOrEqual = ARMAssembler::GE, - LessThan = ARMAssembler::LT, - LessThanOrEqual = ARMAssembler::LE, - Overflow = ARMAssembler::VS, - Signed = ARMAssembler::MI, - Zero = ARMAssembler::EQ, - NonZero = ARMAssembler::NE - }; - - enum DoubleCondition { - // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. - DoubleEqual = ARMAssembler::EQ, - DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial, - DoubleGreaterThan = ARMAssembler::GT, - DoubleGreaterThanOrEqual = ARMAssembler::GE, - DoubleLessThan = ARMAssembler::CC, - DoubleLessThanOrEqual = ARMAssembler::LS, - // If either operand is NaN, these conditions always evaluate to true. - DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial, - DoubleNotEqualOrUnordered = ARMAssembler::NE, - DoubleGreaterThanOrUnordered = ARMAssembler::HI, - DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS, - DoubleLessThanOrUnordered = ARMAssembler::LT, - DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE, - }; - - static const RegisterID stackPointerRegister = ARMRegisters::sp; - static const RegisterID linkRegister = ARMRegisters::lr; - - static const Scale ScalePtr = TimesFour; - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.adds_r(dest, dest, src); - } - - void add32(Imm32 imm, Address address) - { - load32(address, ARMRegisters::S1); - add32(imm, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - } - - void add32(Imm32 imm, RegisterID dest) - { - m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void add32(Address src, RegisterID dest) - { - load32(src, ARMRegisters::S1); - add32(ARMRegisters::S1, dest); - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.ands_r(dest, dest, src); - } - - void and32(Imm32 imm, RegisterID dest) - { - ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); - if (w & ARMAssembler::OP2_INV_IMM) - m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM); - else - m_assembler.ands_r(dest, dest, w); - } - - void lshift32(RegisterID shift_amount, RegisterID dest) - { - ARMWord w = ARMAssembler::getOp2(0x1f); - ASSERT(w != ARMAssembler::INVALID_IMM); - m_assembler.and_r(ARMRegisters::S0, shift_amount, w); - - m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0)); - } - - void lshift32(Imm32 imm, RegisterID dest) - { - m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); - } - - void mul32(RegisterID src, RegisterID dest) - { - if (src == dest) { - move(src, ARMRegisters::S0); - src = ARMRegisters::S0; - } - m_assembler.muls_r(dest, dest, src); - } - - void mul32(Imm32 imm, RegisterID src, RegisterID dest) - { - move(imm, ARMRegisters::S0); - m_assembler.muls_r(dest, src, ARMRegisters::S0); - } - - void neg32(RegisterID srcDest) - { - m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2(0)); - } - - void not32(RegisterID dest) - { - m_assembler.mvns_r(dest, dest); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orrs_r(dest, dest, src); - } - - void or32(Imm32 imm, RegisterID dest) - { - m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void rshift32(RegisterID shift_amount, RegisterID dest) - { - ARMWord w = ARMAssembler::getOp2(0x1f); - ASSERT(w != ARMAssembler::INVALID_IMM); - m_assembler.and_r(ARMRegisters::S0, shift_amount, w); - - m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0)); - } - - void rshift32(Imm32 imm, RegisterID dest) - { - m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); - } - - void urshift32(RegisterID shift_amount, RegisterID dest) - { - ARMWord w = ARMAssembler::getOp2(0x1f); - ASSERT(w != ARMAssembler::INVALID_IMM); - m_assembler.and_r(ARMRegisters::S0, shift_amount, w); - - m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0)); - } - - void urshift32(Imm32 imm, RegisterID dest) - { - m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.subs_r(dest, dest, src); - } - - void sub32(Imm32 imm, RegisterID dest) - { - m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void sub32(Imm32 imm, Address address) - { - load32(address, ARMRegisters::S1); - sub32(imm, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - } - - void sub32(Address src, RegisterID dest) - { - load32(src, ARMRegisters::S1); - sub32(ARMRegisters::S1, dest); - } - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.eors_r(dest, dest, src); - } - - void xor32(Imm32 imm, RegisterID dest) - { - m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void countLeadingZeros32(RegisterID src, RegisterID dest) - { -#if WTF_ARM_ARCH_AT_LEAST(5) - m_assembler.clz_r(dest, src); -#else - UNUSED_PARAM(src); - UNUSED_PARAM(dest); - ASSERT_NOT_REACHED(); -#endif - } - - void load8(ImplicitAddress address, RegisterID dest) - { - m_assembler.dataTransfer32(true, dest, address.base, address.offset, true); - } - - void load32(ImplicitAddress address, RegisterID dest) - { - m_assembler.dataTransfer32(true, dest, address.base, address.offset); - } - - void load32(BaseIndex address, RegisterID dest) - { - m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); - } - -#if CPU(ARMV5_OR_LOWER) - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest); -#else - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - load32(address, dest); - } -#endif - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, 0); - m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0); - return dataLabel; - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - load32(address, dest); - return label; - } - - void load16(BaseIndex address, RegisterID dest) - { - m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale)); - load16(Address(ARMRegisters::S1, address.offset), dest); - } - - void load16(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= 0) - m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0)); - else - m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0)); - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARMRegisters::S0, 0); - m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0); - return dataLabel; - } - - void store32(RegisterID src, ImplicitAddress address) - { - m_assembler.dataTransfer32(false, src, address.base, address.offset); - } - - void store32(RegisterID src, BaseIndex address) - { - m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast<int>(address.scale), address.offset); - } - - void store32(Imm32 imm, ImplicitAddress address) - { - if (imm.m_isPointer) - m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); - else - move(imm, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - } - - void store32(RegisterID src, void* address) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); - m_assembler.dtr_u(false, src, ARMRegisters::S0, 0); - } - - void store32(Imm32 imm, void* address) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); - if (imm.m_isPointer) - m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); - else - m_assembler.moveImm(imm.m_value, ARMRegisters::S1); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); - } - - void pop(RegisterID dest) - { - m_assembler.pop_r(dest); - } - - void push(RegisterID src) - { - m_assembler.push_r(src); - } - - void push(Address address) - { - load32(address, ARMRegisters::S1); - push(ARMRegisters::S1); - } - - void push(Imm32 imm) - { - move(imm, ARMRegisters::S0); - push(ARMRegisters::S0); - } - - void move(Imm32 imm, RegisterID dest) - { - if (imm.m_isPointer) - m_assembler.ldr_un_imm(dest, imm.m_value); - else - m_assembler.moveImm(imm.m_value, dest); - } - - void move(RegisterID src, RegisterID dest) - { - m_assembler.mov_r(dest, src); - } - - void move(ImmPtr imm, RegisterID dest) - { - move(Imm32(imm), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - m_assembler.mov_r(ARMRegisters::S0, reg1); - m_assembler.mov_r(reg1, reg2); - m_assembler.mov_r(reg2, ARMRegisters::S0); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - Jump branch8(Condition cond, Address left, Imm32 right) - { - load8(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0) - { - m_assembler.cmp_r(left, right); - return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); - } - - Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0) - { - if (right.m_isPointer) { - m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value); - m_assembler.cmp_r(left, ARMRegisters::S0); - } else { - ARMWord tmp = m_assembler.getOp2(-right.m_value); - if (tmp != ARMAssembler::INVALID_IMM) - m_assembler.cmn_r(left, tmp); - else - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); - } - return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - load32(right, ARMRegisters::S1); - return branch32(cond, left, ARMRegisters::S1); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - load32(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32(Condition cond, Address left, Imm32 right) - { - load32(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32(Condition cond, BaseIndex left, Imm32 right) - { - load32(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) - { - load32WithUnalignedHalfWords(left, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - UNUSED_PARAM(cond); - UNUSED_PARAM(left); - UNUSED_PARAM(right); - ASSERT_NOT_REACHED(); - return jump(); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) - { - load16(left, ARMRegisters::S0); - move(right, ARMRegisters::S1); - m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1); - return m_assembler.jmp(ARMCondition(cond)); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load8(address, ARMRegisters::S1); - return branchTest32(cond, ARMRegisters::S1, mask); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.tst_r(reg, mask); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true); - if (w & ARMAssembler::OP2_INV_IMM) - m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM); - else - m_assembler.tst_r(reg, w); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load32(address, ARMRegisters::S1); - return branchTest32(cond, ARMRegisters::S1, mask); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - load32(address, ARMRegisters::S1); - return branchTest32(cond, ARMRegisters::S1, mask); - } - - Jump jump() - { - return Jump(m_assembler.jmp()); - } - - void jump(RegisterID target) - { - m_assembler.bx(target); - } - - void jump(Address address) - { - load32(address, ARMRegisters::pc); - } - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(imm, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - void mull32(RegisterID src1, RegisterID src2, RegisterID dest) - { - if (src1 == dest) { - move(src1, ARMRegisters::S0); - src1 = ARMRegisters::S0; - } - m_assembler.mull_r(ARMRegisters::S1, dest, src2, src1); - m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31)); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - mull32(src, dest, dest); - cond = NonZero; - } - else - mul32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - move(imm, ARMRegisters::S0); - mull32(ARMRegisters::S0, src, dest); - cond = NonZero; - } - else - mul32(imm, src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchNeg32(Condition cond, RegisterID srcDest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - neg32(srcDest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); - or32(src, dest); - return Jump(m_assembler.jmp(ARMCondition(cond))); - } - - void breakpoint() - { - m_assembler.bkpt(0); - } - - Call nearCall() - { -#if WTF_ARM_ARCH_AT_LEAST(5) - ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); - m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); - return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear); -#else - prepareCall(); - return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear); -#endif - } - - Call call(RegisterID target) - { - return Call(m_assembler.blx(target), Call::None); - } - - void call(Address address) - { - call32(address.base, address.offset); - } - - void ret() - { - m_assembler.bx(linkRegister); - } - - void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmp_r(left, right); - m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); - } - - void set32Compare32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); - } - - void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - // ARM doesn't have byte registers - set32Compare32(cond, left, right, dest); - } - - void set8Compare32(Condition cond, Address left, RegisterID right, RegisterID dest) - { - // ARM doesn't have byte registers - load32(left, ARMRegisters::S1); - set32Compare32(cond, ARMRegisters::S1, right, dest); - } - - void set8Compare32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - // ARM doesn't have byte registers - set32Compare32(cond, left, right, dest); - } - - void set32Test32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - load32(address, ARMRegisters::S1); - if (mask.m_value == -1) - m_assembler.cmp_r(0, ARMRegisters::S1); - else - m_assembler.tst_r(ARMRegisters::S1, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); - m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); - } - - void set32Test8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - // ARM doesn't have byte registers - set32Test32(cond, address, mask, dest); - } - - void add32(Imm32 imm, RegisterID src, RegisterID dest) - { - m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); - } - - void add32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); - add32(imm, ARMRegisters::S1); - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); - } - - void sub32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); - sub32(imm, ARMRegisters::S1); - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); - } - - void load32(void* address, RegisterID dest) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); - m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - load32(left.m_ptr, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) - { - load32(left.m_ptr, ARMRegisters::S1); - return branch32(cond, ARMRegisters::S1, right); - } - - void relativeTableJump(RegisterID index, int scale) - { - ASSERT(scale >= 0 && scale <= 31); - m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale)); - - // NOP the default prefetching - m_assembler.mov_r(ARMRegisters::r0, ARMRegisters::r0); - } - - Call call() - { -#if WTF_ARM_ARCH_AT_LEAST(5) - ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); - m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); - return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable); -#else - prepareCall(); - return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable); -#endif - } - - Call tailRecursiveCall() - { - return Call::fromTailJump(jump()); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - return Call::fromTailJump(oldJump); - } - - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) - { - DataLabelPtr dataLabel(this); - m_assembler.ldr_un_imm(dest, reinterpret_cast<ARMWord>(initialValue.m_value)); - return dataLabel; - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1); - Jump jump = branch32(cond, left, ARMRegisters::S1, true); - return jump; - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - load32(left, ARMRegisters::S1); - dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); - Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true); - return jump; - } - - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) - { - DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1); - store32(ARMRegisters::S1, address); - return dataLabel; - } - - DataLabelPtr storePtrWithPatch(ImplicitAddress address) - { - return storePtrWithPatch(ImmPtr(0), address); - } - - // Floating point operators - bool supportsFloatingPoint() const - { - return s_isVFPPresent; - } - - bool supportsFloatingPointTruncate() const - { - return s_isVFPPresent; - } - - bool supportsFloatingPointSqrt() const - { - return s_isVFPPresent; - } - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { - m_assembler.doubleTransfer(true, dest, address.base, address.offset); - } - - void loadDouble(const void* address, FPRegisterID dest) - { - m_assembler.ldr_un_imm(ARMRegisters::S0, (ARMWord)address); - m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0); - } - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { - m_assembler.doubleTransfer(false, src, address.base, address.offset); - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vadd_f64_r(dest, dest, src); - } - - void addDouble(Address src, FPRegisterID dest) - { - loadDouble(src, ARMRegisters::SD0); - addDouble(ARMRegisters::SD0, dest); - } - - void divDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vdiv_f64_r(dest, dest, src); - } - - void divDouble(Address src, FPRegisterID dest) - { - ASSERT_NOT_REACHED(); // Untested - loadDouble(src, ARMRegisters::SD0); - divDouble(ARMRegisters::SD0, dest); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vsub_f64_r(dest, dest, src); - } - - void subDouble(Address src, FPRegisterID dest) - { - loadDouble(src, ARMRegisters::SD0); - subDouble(ARMRegisters::SD0, dest); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vmul_f64_r(dest, dest, src); - } - - void mulDouble(Address src, FPRegisterID dest) - { - loadDouble(src, ARMRegisters::SD0); - mulDouble(ARMRegisters::SD0, dest); - } - - void sqrtDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vsqrt_f64_r(dest, src); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.vmov_vfp_r(dest << 1, src); - m_assembler.vcvt_f64_s32_r(dest, dest << 1); - } - - void convertInt32ToDouble(Address src, FPRegisterID dest) - { - ASSERT_NOT_REACHED(); // Untested - // flds does not worth the effort here - load32(src, ARMRegisters::S1); - convertInt32ToDouble(ARMRegisters::S1, dest); - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - ASSERT_NOT_REACHED(); // Untested - // flds does not worth the effort here - m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr); - m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); - convertInt32ToDouble(ARMRegisters::S1, dest); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - m_assembler.vcmp_f64_r(left, right); - m_assembler.vmrs_apsr(); - if (cond & DoubleConditionBitSpecial) - m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); - return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask))); - } - - // Truncates 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, INT_MIN and INT_MAX). - Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) - { - m_assembler.vcvtr_s32_f64_r(ARMRegisters::SD0 << 1, src); - // If VCVTR.S32.F64 can't fit the result into a 32-bit - // integer, it saturates at INT_MAX or INT_MIN. Testing this is - // probably quicker than testing FPSCR for exception. - m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1); - m_assembler.sub_r(ARMRegisters::S0, dest, ARMAssembler::getOp2(0x80000000)); - m_assembler.cmn_r(ARMRegisters::S0, ARMAssembler::getOp2(1), ARMCondition(NotEqual)); - return Jump(m_assembler.jmp(ARMCondition(Equal))); - } - - // Convert 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) - { - m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src); - m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1); - - // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - m_assembler.vcvt_f64_s32_r(ARMRegisters::SD0, ARMRegisters::SD0 << 1); - failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0)); - - // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 - failureCases.append(branchTest32(Zero, dest)); - } - - void zeroDouble(FPRegisterID srcDest) - { - m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0)); - convertInt32ToDouble(ARMRegisters::S0, srcDest); - } - -protected: - ARMAssembler::Condition ARMCondition(Condition cond) - { - return static_cast<ARMAssembler::Condition>(cond); - } - - void ensureSpace(int insnSpace, int constSpace) - { - m_assembler.ensureSpace(insnSpace, constSpace); - } - - int sizeOfConstantPool() - { - return m_assembler.sizeOfConstantPool(); - } - - void prepareCall() - { -#if WTF_ARM_ARCH_VERSION < 5 - ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); - - m_assembler.mov_r(linkRegister, ARMRegisters::pc); -#endif - } - - void call32(RegisterID base, int32_t offset) - { -#if WTF_ARM_ARCH_AT_LEAST(5) - int targetReg = ARMRegisters::S1; -#else - int targetReg = ARMRegisters::pc; -#endif - int tmpReg = ARMRegisters::S1; - - if (base == ARMRegisters::sp) - offset += 4; - - if (offset >= 0) { - if (offset <= 0xfff) { - prepareCall(); - m_assembler.dtr_u(true, targetReg, base, offset); - } else if (offset <= 0xfffff) { - m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); - prepareCall(); - m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff); - } else { - m_assembler.moveImm(offset, tmpReg); - prepareCall(); - m_assembler.dtr_ur(true, targetReg, base, tmpReg); - } - } else { - offset = -offset; - if (offset <= 0xfff) { - prepareCall(); - m_assembler.dtr_d(true, targetReg, base, offset); - } else if (offset <= 0xfffff) { - m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); - prepareCall(); - m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff); - } else { - m_assembler.moveImm(offset, tmpReg); - prepareCall(); - m_assembler.dtr_dr(true, targetReg, base, tmpReg); - } - } -#if WTF_ARM_ARCH_AT_LEAST(5) - m_assembler.blx(targetReg); -#endif - } - -private: - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - ARMAssembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static const bool s_isVFPPresent; -}; - -} - -#endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) - -#endif // MacroAssemblerARM_h diff --git a/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/JavaScriptCore/assembler/MacroAssemblerARMv7.h deleted file mode 100644 index 5980de0..0000000 --- a/JavaScriptCore/assembler/MacroAssemblerARMv7.h +++ /dev/null @@ -1,1356 +0,0 @@ -/* - * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 University of Szeged - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef MacroAssemblerARMv7_h -#define MacroAssemblerARMv7_h - -#if ENABLE(ASSEMBLER) - -#include "ARMv7Assembler.h" -#include "AbstractMacroAssembler.h" - -namespace JSC { - -class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> { - // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7? - // - dTR is likely used more than aTR, and we'll get better instruction - // encoding if it's in the low 8 registers. - static const RegisterID dataTempRegister = ARMRegisters::ip; - static const RegisterID addressTempRegister = ARMRegisters::r3; - - static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7; - inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); } - -public: - typedef ARMv7Assembler::LinkRecord LinkRecord; - typedef ARMv7Assembler::JumpType JumpType; - typedef ARMv7Assembler::JumpLinkType JumpLinkType; - - MacroAssemblerARMv7() - : m_inUninterruptedSequence(false) - { - } - - void beginUninterruptedSequence() { m_inUninterruptedSequence = true; } - void endUninterruptedSequence() { m_inUninterruptedSequence = false; } - Vector<LinkRecord>& jumpsToLink() { return m_assembler.jumpsToLink(); } - void* unlinkedCode() { return m_assembler.unlinkedCode(); } - bool canCompact(JumpType jumpType) { return m_assembler.canCompact(jumpType); } - JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(jumpType, from, to); } - JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(record, from, to); } - void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); } - int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return m_assembler.jumpSizeDelta(jumpType, jumpLinkType); } - void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return m_assembler.link(record, from, to); } - - struct ArmAddress { - enum AddressType { - HasOffset, - HasIndex, - } type; - RegisterID base; - union { - int32_t offset; - struct { - RegisterID index; - Scale scale; - }; - } u; - - explicit ArmAddress(RegisterID base, int32_t offset = 0) - : type(HasOffset) - , base(base) - { - u.offset = offset; - } - - explicit ArmAddress(RegisterID base, RegisterID index, Scale scale = TimesOne) - : type(HasIndex) - , base(base) - { - u.index = index; - u.scale = scale; - } - }; - -public: - typedef ARMRegisters::FPDoubleRegisterID FPRegisterID; - - static const Scale ScalePtr = TimesFour; - - enum Condition { - Equal = ARMv7Assembler::ConditionEQ, - NotEqual = ARMv7Assembler::ConditionNE, - Above = ARMv7Assembler::ConditionHI, - AboveOrEqual = ARMv7Assembler::ConditionHS, - Below = ARMv7Assembler::ConditionLO, - BelowOrEqual = ARMv7Assembler::ConditionLS, - GreaterThan = ARMv7Assembler::ConditionGT, - GreaterThanOrEqual = ARMv7Assembler::ConditionGE, - LessThan = ARMv7Assembler::ConditionLT, - LessThanOrEqual = ARMv7Assembler::ConditionLE, - Overflow = ARMv7Assembler::ConditionVS, - Signed = ARMv7Assembler::ConditionMI, - Zero = ARMv7Assembler::ConditionEQ, - NonZero = ARMv7Assembler::ConditionNE - }; - enum DoubleCondition { - // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. - DoubleEqual = ARMv7Assembler::ConditionEQ, - DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently. - DoubleGreaterThan = ARMv7Assembler::ConditionGT, - DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE, - DoubleLessThan = ARMv7Assembler::ConditionLO, - DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS, - // If either operand is NaN, these conditions always evaluate to true. - DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently. - DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE, - DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI, - DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS, - DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT, - DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE, - }; - - static const RegisterID stackPointerRegister = ARMRegisters::sp; - static const RegisterID linkRegister = ARMRegisters::lr; - - // Integer arithmetic operations: - // - // Operations are typically two operand - operation(source, srcDst) - // For many operations the source may be an Imm32, the srcDst operand - // may often be a memory location (explictly described using an Address - // object). - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.add(dest, dest, src); - } - - void add32(Imm32 imm, RegisterID dest) - { - add32(imm, dest, dest); - } - - void add32(Imm32 imm, RegisterID src, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.add(dest, src, armImm); - else { - move(imm, dataTempRegister); - m_assembler.add(dest, src, dataTempRegister); - } - } - - void add32(Imm32 imm, Address address) - { - load32(address, dataTempRegister); - - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.add(dataTempRegister, dataTempRegister, armImm); - else { - // Hrrrm, since dataTempRegister holds the data loaded, - // use addressTempRegister to hold the immediate. - move(imm, addressTempRegister); - m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); - } - - store32(dataTempRegister, address); - } - - void add32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - add32(dataTempRegister, dest); - } - - void add32(Imm32 imm, AbsoluteAddress address) - { - load32(address.m_ptr, dataTempRegister); - - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.add(dataTempRegister, dataTempRegister, armImm); - else { - // Hrrrm, since dataTempRegister holds the data loaded, - // use addressTempRegister to hold the immediate. - move(imm, addressTempRegister); - m_assembler.add(dataTempRegister, dataTempRegister, addressTempRegister); - } - - store32(dataTempRegister, address.m_ptr); - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.ARM_and(dest, dest, src); - } - - void and32(Imm32 imm, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.ARM_and(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.ARM_and(dest, dest, dataTempRegister); - } - } - - void countLeadingZeros32(RegisterID src, RegisterID dest) - { - m_assembler.clz(dest, src); - } - - void lshift32(RegisterID shift_amount, RegisterID dest) - { - // Clamp the shift to the range 0..31 - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); - ASSERT(armImm.isValid()); - m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); - - m_assembler.lsl(dest, dest, dataTempRegister); - } - - void lshift32(Imm32 imm, RegisterID dest) - { - m_assembler.lsl(dest, dest, imm.m_value & 0x1f); - } - - void mul32(RegisterID src, RegisterID dest) - { - m_assembler.smull(dest, dataTempRegister, dest, src); - } - - void mul32(Imm32 imm, RegisterID src, RegisterID dest) - { - move(imm, dataTempRegister); - m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); - } - - void neg32(RegisterID srcDest) - { - m_assembler.neg(srcDest, srcDest); - } - - void not32(RegisterID srcDest) - { - m_assembler.mvn(srcDest, srcDest); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orr(dest, dest, src); - } - - void or32(Imm32 imm, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.orr(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.orr(dest, dest, dataTempRegister); - } - } - - void rshift32(RegisterID shift_amount, RegisterID dest) - { - // Clamp the shift to the range 0..31 - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); - ASSERT(armImm.isValid()); - m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); - - m_assembler.asr(dest, dest, dataTempRegister); - } - - void rshift32(Imm32 imm, RegisterID dest) - { - m_assembler.asr(dest, dest, imm.m_value & 0x1f); - } - - void urshift32(RegisterID shift_amount, RegisterID dest) - { - // Clamp the shift to the range 0..31 - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); - ASSERT(armImm.isValid()); - m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); - - m_assembler.lsr(dest, dest, dataTempRegister); - } - - void urshift32(Imm32 imm, RegisterID dest) - { - m_assembler.lsr(dest, dest, imm.m_value & 0x1f); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.sub(dest, dest, src); - } - - void sub32(Imm32 imm, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.sub(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.sub(dest, dest, dataTempRegister); - } - } - - void sub32(Imm32 imm, Address address) - { - load32(address, dataTempRegister); - - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.sub(dataTempRegister, dataTempRegister, armImm); - else { - // Hrrrm, since dataTempRegister holds the data loaded, - // use addressTempRegister to hold the immediate. - move(imm, addressTempRegister); - m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); - } - - store32(dataTempRegister, address); - } - - void sub32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - sub32(dataTempRegister, dest); - } - - void sub32(Imm32 imm, AbsoluteAddress address) - { - load32(address.m_ptr, dataTempRegister); - - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12OrEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.sub(dataTempRegister, dataTempRegister, armImm); - else { - // Hrrrm, since dataTempRegister holds the data loaded, - // use addressTempRegister to hold the immediate. - move(imm, addressTempRegister); - m_assembler.sub(dataTempRegister, dataTempRegister, addressTempRegister); - } - - store32(dataTempRegister, address.m_ptr); - } - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.eor(dest, dest, src); - } - - void xor32(Imm32 imm, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.eor(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.eor(dest, dest, dataTempRegister); - } - } - - - // Memory access operations: - // - // Loads are of the form load(address, destination) and stores of the form - // store(source, address). The source for a store may be an Imm32. Address - // operand objects to loads and store will be implicitly constructed if a - // register is passed. - -private: - void load32(ArmAddress address, RegisterID dest) - { - if (address.type == ArmAddress::HasIndex) - m_assembler.ldr(dest, address.base, address.u.index, address.u.scale); - else if (address.u.offset >= 0) { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); - ASSERT(armImm.isValid()); - m_assembler.ldr(dest, address.base, armImm); - } else { - ASSERT(address.u.offset >= -255); - m_assembler.ldr(dest, address.base, address.u.offset, true, false); - } - } - - void load16(ArmAddress address, RegisterID dest) - { - if (address.type == ArmAddress::HasIndex) - m_assembler.ldrh(dest, address.base, address.u.index, address.u.scale); - else if (address.u.offset >= 0) { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); - ASSERT(armImm.isValid()); - m_assembler.ldrh(dest, address.base, armImm); - } else { - ASSERT(address.u.offset >= -255); - m_assembler.ldrh(dest, address.base, address.u.offset, true, false); - } - } - - void load8(ArmAddress address, RegisterID dest) - { - if (address.type == ArmAddress::HasIndex) - m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale); - else if (address.u.offset >= 0) { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); - ASSERT(armImm.isValid()); - m_assembler.ldrb(dest, address.base, armImm); - } else { - ASSERT(address.u.offset >= -255); - m_assembler.ldrb(dest, address.base, address.u.offset, true, false); - } - } - - void store32(RegisterID src, ArmAddress address) - { - if (address.type == ArmAddress::HasIndex) - m_assembler.str(src, address.base, address.u.index, address.u.scale); - else if (address.u.offset >= 0) { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); - ASSERT(armImm.isValid()); - m_assembler.str(src, address.base, armImm); - } else { - ASSERT(address.u.offset >= -255); - m_assembler.str(src, address.base, address.u.offset, true, false); - } - } - -public: - void load32(ImplicitAddress address, RegisterID dest) - { - load32(setupArmAddress(address), dest); - } - - void load32(BaseIndex address, RegisterID dest) - { - load32(setupArmAddress(address), dest); - } - - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - load32(setupArmAddress(address), dest); - } - - void load32(void* address, RegisterID dest) - { - move(ImmPtr(address), addressTempRegister); - m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); - } - - void load8(ImplicitAddress address, RegisterID dest) - { - load8(setupArmAddress(address), dest); - } - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); - load32(ArmAddress(address.base, dataTempRegister), dest); - return label; - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - moveFixedWidthEncoding(Imm32(address.offset), dataTempRegister); - load32(ArmAddress(address.base, dataTempRegister), dest); - return label; - } - - void load16(BaseIndex address, RegisterID dest) - { - m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); - } - - void load16(ImplicitAddress address, RegisterID dest) - { - ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset); - if (armImm.isValid()) - m_assembler.ldrh(dest, address.base, armImm); - else { - move(Imm32(address.offset), dataTempRegister); - m_assembler.ldrh(dest, address.base, dataTempRegister); - } - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); - store32(src, ArmAddress(address.base, dataTempRegister)); - return label; - } - - void store32(RegisterID src, ImplicitAddress address) - { - store32(src, setupArmAddress(address)); - } - - void store32(RegisterID src, BaseIndex address) - { - store32(src, setupArmAddress(address)); - } - - void store32(Imm32 imm, ImplicitAddress address) - { - move(imm, dataTempRegister); - store32(dataTempRegister, setupArmAddress(address)); - } - - void store32(RegisterID src, void* address) - { - move(ImmPtr(address), addressTempRegister); - m_assembler.str(src, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); - } - - void store32(Imm32 imm, void* address) - { - move(imm, dataTempRegister); - store32(dataTempRegister, address); - } - - - // Floating-point operations: - - bool supportsFloatingPoint() const { return true; } - // On x86(_64) the MacroAssembler provides an interface to truncate a double to an integer. - // If a value is not representable as an integer, and possibly for some values that are, - // (on x86 INT_MIN, since this is indistinguishable from results for out-of-range/NaN input) - // a branch will be taken. It is not clear whether this interface will be well suited to - // other platforms. On ARMv7 the hardware truncation operation produces multiple possible - // failure values (saturates to INT_MIN & INT_MAX, NaN reulsts in a value of 0). This is a - // temporary solution while we work out what this interface should be. Either we need to - // decide to make this interface work on all platforms, rework the interface to make it more - // generic, or decide that the MacroAssembler cannot practically be used to abstracted these - // operations, and make clients go directly to the m_assembler to plant truncation instructions. - // In short, FIXME:. - bool supportsFloatingPointTruncate() const { return false; } - - bool supportsFloatingPointSqrt() const - { - return false; - } - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { - RegisterID base = address.base; - int32_t offset = address.offset; - - // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. - if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { - add32(Imm32(offset), base, addressTempRegister); - base = addressTempRegister; - offset = 0; - } - - m_assembler.vldr(dest, base, offset); - } - - void loadDouble(const void* address, FPRegisterID dest) - { - move(ImmPtr(address), addressTempRegister); - m_assembler.vldr(dest, addressTempRegister, 0); - } - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { - RegisterID base = address.base; - int32_t offset = address.offset; - - // Arm vfp addresses can be offset by a 9-bit ones-comp immediate, left shifted by 2. - if ((offset & 3) || (offset > (255 * 4)) || (offset < -(255 * 4))) { - add32(Imm32(offset), base, addressTempRegister); - base = addressTempRegister; - offset = 0; - } - - m_assembler.vstr(src, base, offset); - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vadd_F64(dest, dest, src); - } - - void addDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - addDouble(fpTempRegister, dest); - } - - void divDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vdiv_F64(dest, dest, src); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vsub_F64(dest, dest, src); - } - - void subDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - subDouble(fpTempRegister, dest); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.vmul_F64(dest, dest, src); - } - - void mulDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - mulDouble(fpTempRegister, dest); - } - - void sqrtDouble(FPRegisterID, FPRegisterID) - { - ASSERT_NOT_REACHED(); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.vmov(fpTempRegisterAsSingle(), src); - m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle()); - } - - void convertInt32ToDouble(Address address, FPRegisterID dest) - { - // Fixme: load directly into the fpr! - load32(address, dataTempRegister); - m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister); - m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle()); - } - - void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest) - { - // Fixme: load directly into the fpr! - load32(address.m_ptr, dataTempRegister); - m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister); - m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle()); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - m_assembler.vcmp_F64(left, right); - m_assembler.vmrs(); - - if (cond == DoubleNotEqual) { - // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump. - Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); - Jump result = makeBranch(ARMv7Assembler::ConditionNE); - unordered.link(this); - return result; - } - if (cond == DoubleEqualOrUnordered) { - Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); - Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE); - unordered.link(this); - // We get here if either unordered, or equal. - Jump result = makeJump(); - notEqual.link(this); - return result; - } - return makeBranch(cond); - } - - Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID) - { - ASSERT_NOT_REACHED(); - return jump(); - } - - // Convert 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID) - { - m_assembler.vcvtr_S32_F64(fpTempRegisterAsSingle(), src); - m_assembler.vmov(dest, fpTempRegisterAsSingle()); - - // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - m_assembler.vcvt_F64_S32(fpTempRegister, fpTempRegisterAsSingle()); - failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister)); - - // If the result is zero, it might have been -0.0, and the double comparison won't catch this! - failureCases.append(branchTest32(Zero, dest)); - } - - void zeroDouble(FPRegisterID dest) - { - m_assembler.vmov_F64_0(dest); - } - - // Stack manipulation operations: - // - // The ABI is assumed to provide a stack abstraction to memory, - // containing machine word sized units of data. Push and pop - // operations add and remove a single register sized unit of data - // to or from the stack. Peek and poke operations read or write - // values on the stack, without moving the current stack position. - - void pop(RegisterID dest) - { - // store postindexed with writeback - m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true); - } - - void push(RegisterID src) - { - // store preindexed with writeback - m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true); - } - - void push(Address address) - { - load32(address, dataTempRegister); - push(dataTempRegister); - } - - void push(Imm32 imm) - { - move(imm, dataTempRegister); - push(dataTempRegister); - } - - // Register move operations: - // - // Move values in registers. - - void move(Imm32 imm, RegisterID dest) - { - uint32_t value = imm.m_value; - - if (imm.m_isPointer) - moveFixedWidthEncoding(imm, dest); - else { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(value); - - if (armImm.isValid()) - m_assembler.mov(dest, armImm); - else if ((armImm = ARMThumbImmediate::makeEncodedImm(~value)).isValid()) - m_assembler.mvn(dest, armImm); - else { - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(value)); - if (value & 0xffff0000) - m_assembler.movt(dest, ARMThumbImmediate::makeUInt16(value >> 16)); - } - } - } - - void move(RegisterID src, RegisterID dest) - { - m_assembler.mov(dest, src); - } - - void move(ImmPtr imm, RegisterID dest) - { - move(Imm32(imm), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - move(reg1, dataTempRegister); - move(reg2, reg1); - move(dataTempRegister, reg2); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest) - move(src, dest); - } - - - // Forwards / external control flow operations: - // - // This set of jump and conditional branch operations return a Jump - // object which may linked at a later point, allow forwards jump, - // or jumps that will require external linkage (after the code has been - // relocated). - // - // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge - // respecitvely, for unsigned comparisons the names b, a, be, and ae are - // used (representing the names 'below' and 'above'). - // - // Operands to the comparision are provided in the expected order, e.g. - // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when - // treated as a signed 32bit value, is less than or equal to 5. - // - // jz and jnz test whether the first operand is equal to zero, and take - // an optional second operand of a mask under which to perform the test. -private: - - // Should we be using TEQ for equal/not-equal? - void compare32(RegisterID left, Imm32 right) - { - int32_t imm = right.m_value; - if (!imm) - m_assembler.tst(left, left); - else { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); - if (armImm.isValid()) - m_assembler.cmp(left, armImm); - if ((armImm = ARMThumbImmediate::makeEncodedImm(-imm)).isValid()) - m_assembler.cmn(left, armImm); - else { - move(Imm32(imm), dataTempRegister); - m_assembler.cmp(left, dataTempRegister); - } - } - } - - void test32(RegisterID reg, Imm32 mask) - { - int32_t imm = mask.m_value; - - if (imm == -1) - m_assembler.tst(reg, reg); - else { - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm); - if (armImm.isValid()) - m_assembler.tst(reg, armImm); - else { - move(mask, dataTempRegister); - m_assembler.tst(reg, dataTempRegister); - } - } - } - -public: - Jump branch32(Condition cond, RegisterID left, RegisterID right) - { - m_assembler.cmp(left, right); - return Jump(makeBranch(cond)); - } - - Jump branch32(Condition cond, RegisterID left, Imm32 right) - { - compare32(left, right); - return Jump(makeBranch(cond)); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - load32(right, dataTempRegister); - return branch32(cond, left, dataTempRegister); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - load32(left, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch32(Condition cond, Address left, Imm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load32(left, addressTempRegister); - return branch32(cond, addressTempRegister, right); - } - - Jump branch32(Condition cond, BaseIndex left, Imm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load32(left, addressTempRegister); - return branch32(cond, addressTempRegister, right); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load32WithUnalignedHalfWords(left, addressTempRegister); - return branch32(cond, addressTempRegister, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - load32(left.m_ptr, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load32(left.m_ptr, addressTempRegister); - return branch32(cond, addressTempRegister, right); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - load16(left, dataTempRegister); - m_assembler.lsl(addressTempRegister, right, 16); - m_assembler.lsl(dataTempRegister, dataTempRegister, 16); - return branch32(cond, dataTempRegister, addressTempRegister); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) - { - // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ - load16(left, addressTempRegister); - m_assembler.lsl(addressTempRegister, addressTempRegister, 16); - return branch32(cond, addressTempRegister, Imm32(right.m_value << 16)); - } - - Jump branch8(Condition cond, RegisterID left, Imm32 right) - { - compare32(left, right); - return Jump(makeBranch(cond)); - } - - Jump branch8(Condition cond, Address left, Imm32 right) - { - // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/ - load8(left, addressTempRegister); - return branch8(cond, addressTempRegister, right); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.tst(reg, mask); - return Jump(makeBranch(cond)); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - test32(reg, mask); - return Jump(makeBranch(cond)); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ - load32(address, addressTempRegister); - return branchTest32(cond, addressTempRegister, mask); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - // use addressTempRegister incase the branchTest32 we call uses dataTempRegister. :-/ - load32(address, addressTempRegister); - return branchTest32(cond, addressTempRegister, mask); - } - - Jump branchTest8(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - test32(reg, mask); - return Jump(makeBranch(cond)); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ - load8(address, addressTempRegister); - return branchTest8(cond, addressTempRegister, mask); - } - - Jump jump() - { - return Jump(makeJump()); - } - - void jump(RegisterID target) - { - m_assembler.bx(target, ARMv7Assembler::JumpFixed); - } - - // Address is a memory location containing the address to jump to - void jump(Address address) - { - load32(address, dataTempRegister); - m_assembler.bx(dataTempRegister, ARMv7Assembler::JumpFixed); - } - - - // Arithmetic control flow operations: - // - // This set of conditional branch operations branch based - // on the result of an arithmetic operation. The operation - // is performed as normal, storing the result. - // - // * jz operations branch if the result is zero. - // * jo operations branch if the (signed) arithmetic - // operation caused an overflow to occur. - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.add_S(dest, dest, src); - return Jump(makeBranch(cond)); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.add_S(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.add_S(dest, dest, dataTempRegister); - } - return Jump(makeBranch(cond)); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT_UNUSED(cond, cond == Overflow); - m_assembler.smull(dest, dataTempRegister, dest, src); - m_assembler.asr(addressTempRegister, dest, 31); - return branch32(NotEqual, addressTempRegister, dataTempRegister); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - ASSERT_UNUSED(cond, cond == Overflow); - move(imm, dataTempRegister); - m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); - m_assembler.asr(addressTempRegister, dest, 31); - return branch32(NotEqual, addressTempRegister, dataTempRegister); - } - - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.orr_S(dest, dest, src); - return Jump(makeBranch(cond)); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - m_assembler.sub_S(dest, dest, src); - return Jump(makeBranch(cond)); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(imm.m_value); - if (armImm.isValid()) - m_assembler.sub_S(dest, dest, armImm); - else { - move(imm, dataTempRegister); - m_assembler.sub_S(dest, dest, dataTempRegister); - } - return Jump(makeBranch(cond)); - } - - void relativeTableJump(RegisterID index, int scale) - { - ASSERT(scale >= 0 && scale <= 31); - - // dataTempRegister will point after the jump if index register contains zero - move(ARMRegisters::pc, dataTempRegister); - m_assembler.add(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(9)); - - ShiftTypeAndAmount shift(SRType_LSL, scale); - m_assembler.add(dataTempRegister, dataTempRegister, index, shift); - jump(dataTempRegister); - } - - // Miscellaneous operations: - - void breakpoint() - { - m_assembler.bkpt(0); - } - - Call nearCall() - { - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFixed), Call::LinkableNear); - } - - Call call() - { - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFixed), Call::Linkable); - } - - Call call(RegisterID target) - { - return Call(m_assembler.blx(target, ARMv7Assembler::JumpFixed), Call::None); - } - - Call call(Address address) - { - load32(address, dataTempRegister); - return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFixed), Call::None); - } - - void ret() - { - m_assembler.bx(linkRegister, ARMv7Assembler::JumpFixed); - } - - void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmp(left, right); - m_assembler.it(armV7Condition(cond), false); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); - } - - void set32Compare32(Condition cond, Address left, RegisterID right, RegisterID dest) - { - load32(left, dataTempRegister); - set32Compare32(cond, dataTempRegister, right, dest); - } - - void set32Compare32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - compare32(left, right); - m_assembler.it(armV7Condition(cond), false); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); - } - - void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - set32Compare32(cond, left, right, dest); - } - - void set8Compare32(Condition cond, Address left, RegisterID right, RegisterID dest) - { - set32Compare32(cond, left, right, dest); - } - - void set8Compare32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - set32Compare32(cond, left, right, dest); - } - - // FIXME: - // The mask should be optional... paerhaps the argument order should be - // dest-src, operations always have a dest? ... possibly not true, considering - // asm ops like test, or pseudo ops like pop(). - void set32Test32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - load32(address, dataTempRegister); - test32(dataTempRegister, mask); - m_assembler.it(armV7Condition(cond), false); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); - } - - void set32Test8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - load8(address, dataTempRegister); - test32(dataTempRegister, mask); - m_assembler.it(armV7Condition(cond), false); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); - m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); - } - - DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst) - { - moveFixedWidthEncoding(imm, dst); - return DataLabel32(this); - } - - DataLabelPtr moveWithPatch(ImmPtr imm, RegisterID dst) - { - moveFixedWidthEncoding(Imm32(imm), dst); - return DataLabelPtr(this); - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, dataTempRegister); - return branch32(cond, left, dataTempRegister); - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - load32(left, addressTempRegister); - dataLabel = moveWithPatch(initialRightValue, dataTempRegister); - return branch32(cond, addressTempRegister, dataTempRegister); - } - - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) - { - DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister); - store32(dataTempRegister, address); - return label; - } - DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(ImmPtr(0), address); } - - - Call tailRecursiveCall() - { - // Like a normal call, but don't link. - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.bx(dataTempRegister, ARMv7Assembler::JumpFixed), Call::Linkable); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - oldJump.link(this); - return tailRecursiveCall(); - } - - - int executableOffsetFor(int location) - { - return m_assembler.executableOffsetFor(location); - } - -protected: - bool inUninterruptedSequence() - { - return m_inUninterruptedSequence; - } - - ARMv7Assembler::JmpSrc makeJump() - { - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return m_assembler.bx(dataTempRegister, inUninterruptedSequence() ? ARMv7Assembler::JumpNoConditionFixedSize : ARMv7Assembler::JumpNoCondition); - } - - ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond) - { - m_assembler.it(cond, true, true); - moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return m_assembler.bx(dataTempRegister, inUninterruptedSequence() ? ARMv7Assembler::JumpConditionFixedSize : ARMv7Assembler::JumpCondition, cond); - } - ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); } - ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); } - - ArmAddress setupArmAddress(BaseIndex address) - { - if (address.offset) { - ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); - if (imm.isValid()) - m_assembler.add(addressTempRegister, address.base, imm); - else { - move(Imm32(address.offset), addressTempRegister); - m_assembler.add(addressTempRegister, addressTempRegister, address.base); - } - - return ArmAddress(addressTempRegister, address.index, address.scale); - } else - return ArmAddress(address.base, address.index, address.scale); - } - - ArmAddress setupArmAddress(Address address) - { - if ((address.offset >= -0xff) && (address.offset <= 0xfff)) - return ArmAddress(address.base, address.offset); - - move(Imm32(address.offset), addressTempRegister); - return ArmAddress(address.base, addressTempRegister); - } - - ArmAddress setupArmAddress(ImplicitAddress address) - { - if ((address.offset >= -0xff) && (address.offset <= 0xfff)) - return ArmAddress(address.base, address.offset); - - move(Imm32(address.offset), addressTempRegister); - return ArmAddress(address.base, addressTempRegister); - } - - RegisterID makeBaseIndexBase(BaseIndex address) - { - if (!address.offset) - return address.base; - - ARMThumbImmediate imm = ARMThumbImmediate::makeUInt12OrEncodedImm(address.offset); - if (imm.isValid()) - m_assembler.add(addressTempRegister, address.base, imm); - else { - move(Imm32(address.offset), addressTempRegister); - m_assembler.add(addressTempRegister, addressTempRegister, address.base); - } - - return addressTempRegister; - } - - void moveFixedWidthEncoding(Imm32 imm, RegisterID dst) - { - uint32_t value = imm.m_value; - m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff)); - m_assembler.movt(dst, ARMThumbImmediate::makeUInt16(value >> 16)); - } - - ARMv7Assembler::Condition armV7Condition(Condition cond) - { - return static_cast<ARMv7Assembler::Condition>(cond); - } - - ARMv7Assembler::Condition armV7Condition(DoubleCondition cond) - { - return static_cast<ARMv7Assembler::Condition>(cond); - } - -private: - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - ARMv7Assembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - bool m_inUninterruptedSequence; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // MacroAssemblerARMv7_h diff --git a/JavaScriptCore/assembler/MacroAssemblerCodeRef.h b/JavaScriptCore/assembler/MacroAssemblerCodeRef.h deleted file mode 100644 index 543b0fa..0000000 --- a/JavaScriptCore/assembler/MacroAssemblerCodeRef.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef MacroAssemblerCodeRef_h -#define MacroAssemblerCodeRef_h - -#include "ExecutableAllocator.h" -#include "PassRefPtr.h" -#include "RefPtr.h" -#include "UnusedParam.h" - -#if ENABLE(ASSEMBLER) - -// ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid -// instruction address on the platform (for example, check any alignment requirements). -#if CPU(ARM_THUMB2) -// ARM/thumb instructions must be 16-bit aligned, but all code pointers to be loaded -// into the processor are decorated with the bottom bit set, indicating that this is -// thumb code (as oposed to 32-bit traditional ARM). The first test checks for both -// decorated and undectorated null, and the second test ensures that the pointer is -// decorated. -#define ASSERT_VALID_CODE_POINTER(ptr) \ - ASSERT(reinterpret_cast<intptr_t>(ptr) & ~1); \ - ASSERT(reinterpret_cast<intptr_t>(ptr) & 1) -#define ASSERT_VALID_CODE_OFFSET(offset) \ - ASSERT(!(offset & 1)) // Must be multiple of 2. -#else -#define ASSERT_VALID_CODE_POINTER(ptr) \ - ASSERT(ptr) -#define ASSERT_VALID_CODE_OFFSET(offset) // Anything goes! -#endif - -namespace JSC { - -// FunctionPtr: -// -// FunctionPtr should be used to wrap pointers to C/C++ functions in JSC -// (particularly, the stub functions). -class FunctionPtr { -public: - FunctionPtr() - : m_value(0) - { - } - - template<typename FunctionType> - explicit FunctionPtr(FunctionType* value) -#if COMPILER(RVCT) - // RVTC compiler needs C-style cast as it fails with the following error - // Error: #694: reinterpret_cast cannot cast away const or other type qualifiers - : m_value((void*)(value)) -#else - : m_value(reinterpret_cast<void*>(value)) -#endif - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - void* value() const { return m_value; } - void* executableAddress() const { return m_value; } - - -private: - void* m_value; -}; - -// ReturnAddressPtr: -// -// ReturnAddressPtr should be used to wrap return addresses generated by processor -// 'call' instructions exectued in JIT code. We use return addresses to look up -// exception and optimization information, and to repatch the call instruction -// that is the source of the return address. -class ReturnAddressPtr { -public: - ReturnAddressPtr() - : m_value(0) - { - } - - explicit ReturnAddressPtr(void* value) - : m_value(value) - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - explicit ReturnAddressPtr(FunctionPtr function) - : m_value(function.value()) - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - void* value() const { return m_value; } - -private: - void* m_value; -}; - -// MacroAssemblerCodePtr: -// -// MacroAssemblerCodePtr should be used to wrap pointers to JIT generated code. -class MacroAssemblerCodePtr { -public: - MacroAssemblerCodePtr() - : m_value(0) - { - } - - explicit MacroAssemblerCodePtr(void* value) -#if CPU(ARM_THUMB2) - // Decorate the pointer as a thumb code pointer. - : m_value(reinterpret_cast<char*>(value) + 1) -#else - : m_value(value) -#endif - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - explicit MacroAssemblerCodePtr(ReturnAddressPtr ra) - : m_value(ra.value()) - { - ASSERT_VALID_CODE_POINTER(m_value); - } - - void* executableAddress() const { return m_value; } -#if CPU(ARM_THUMB2) - // To use this pointer as a data address remove the decoration. - void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return reinterpret_cast<char*>(m_value) - 1; } -#else - void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return m_value; } -#endif - - bool operator!() - { - return !m_value; - } - -private: - void* m_value; -}; - -// MacroAssemblerCodeRef: -// -// A reference to a section of JIT generated code. A CodeRef consists of a -// pointer to the code, and a ref pointer to the pool from within which it -// was allocated. -class MacroAssemblerCodeRef { -public: - MacroAssemblerCodeRef() - : m_size(0) - { - } - - MacroAssemblerCodeRef(void* code, PassRefPtr<ExecutablePool> executablePool, size_t size) - : m_code(code) - , m_executablePool(executablePool) - , m_size(size) - { - } - - MacroAssemblerCodePtr m_code; - RefPtr<ExecutablePool> m_executablePool; - size_t m_size; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // MacroAssemblerCodeRef_h diff --git a/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/JavaScriptCore/assembler/MacroAssemblerMIPS.h deleted file mode 100644 index 41f0152..0000000 --- a/JavaScriptCore/assembler/MacroAssemblerMIPS.h +++ /dev/null @@ -1,1859 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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. - */ - -#ifndef MacroAssemblerMIPS_h -#define MacroAssemblerMIPS_h - -#if ENABLE(ASSEMBLER) && CPU(MIPS) - -#include "AbstractMacroAssembler.h" -#include "MIPSAssembler.h" - -namespace JSC { - -class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> { -public: - typedef MIPSRegisters::FPRegisterID FPRegisterID; - - MacroAssemblerMIPS() - : m_fixedWidth(false) - { - } - - static const Scale ScalePtr = TimesFour; - - // For storing immediate number - static const RegisterID immTempRegister = MIPSRegisters::t0; - // For storing data loaded from the memory - static const RegisterID dataTempRegister = MIPSRegisters::t1; - // For storing address base - static const RegisterID addrTempRegister = MIPSRegisters::t2; - // For storing compare result - static const RegisterID cmpTempRegister = MIPSRegisters::t3; - - // FP temp register - static const FPRegisterID fpTempRegister = MIPSRegisters::f16; - - enum Condition { - Equal, - NotEqual, - Above, - AboveOrEqual, - Below, - BelowOrEqual, - GreaterThan, - GreaterThanOrEqual, - LessThan, - LessThanOrEqual, - Overflow, - Signed, - Zero, - NonZero - }; - - enum DoubleCondition { - DoubleEqual, - DoubleNotEqual, - DoubleGreaterThan, - DoubleGreaterThanOrEqual, - DoubleLessThan, - DoubleLessThanOrEqual, - DoubleEqualOrUnordered, - DoubleNotEqualOrUnordered, - DoubleGreaterThanOrUnordered, - DoubleGreaterThanOrEqualOrUnordered, - DoubleLessThanOrUnordered, - DoubleLessThanOrEqualOrUnordered - }; - - static const RegisterID stackPointerRegister = MIPSRegisters::sp; - static const RegisterID returnAddressRegister = MIPSRegisters::ra; - - // Integer arithmetic operations: - // - // Operations are typically two operand - operation(source, srcDst) - // For many operations the source may be an Imm32, the srcDst operand - // may often be a memory location (explictly described using an Address - // object). - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.addu(dest, dest, src); - } - - void add32(Imm32 imm, RegisterID dest) - { - add32(imm, dest, dest); - } - - void add32(Imm32 imm, RegisterID src, RegisterID dest) - { - if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767 - && !m_fixedWidth) { - /* - addiu dest, src, imm - */ - m_assembler.addiu(dest, src, imm.m_value); - } else { - /* - li immTemp, imm - addu dest, src, immTemp - */ - move(imm, immTempRegister); - m_assembler.addu(dest, src, immTempRegister); - } - } - - void add32(Imm32 imm, Address address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - lw dataTemp, offset(base) - li immTemp, imm - addu dataTemp, dataTemp, immTemp - sw dataTemp, offset(base) - */ - m_assembler.lw(dataTempRegister, address.base, address.offset); - if (!imm.m_isPointer - && imm.m_value >= -32768 && imm.m_value <= 32767 - && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, - imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.addu(dataTempRegister, dataTempRegister, - immTempRegister); - } - m_assembler.sw(dataTempRegister, address.base, address.offset); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lw dataTemp, (offset & 0xffff)(addrTemp) - li immtemp, imm - addu dataTemp, dataTemp, immTemp - sw dataTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dataTempRegister, addrTempRegister, address.offset); - - if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, - imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.addu(dataTempRegister, dataTempRegister, - immTempRegister); - } - m_assembler.sw(dataTempRegister, addrTempRegister, address.offset); - } - } - - void add32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - add32(dataTempRegister, dest); - } - - void add32(RegisterID src, Address dest) - { - if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) { - /* - lw dataTemp, offset(base) - addu dataTemp, dataTemp, src - sw dataTemp, offset(base) - */ - m_assembler.lw(dataTempRegister, dest.base, dest.offset); - m_assembler.addu(dataTempRegister, dataTempRegister, src); - m_assembler.sw(dataTempRegister, dest.base, dest.offset); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lw dataTemp, (offset & 0xffff)(addrTemp) - addu dataTemp, dataTemp, src - sw dataTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, dest.base); - m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset); - m_assembler.addu(dataTempRegister, dataTempRegister, src); - m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset); - } - } - - void add32(Imm32 imm, AbsoluteAddress address) - { - /* - li addrTemp, address - li immTemp, imm - lw dataTemp, 0(addrTemp) - addu dataTemp, dataTemp, immTemp - sw dataTemp, 0(addrTemp) - */ - move(ImmPtr(address.m_ptr), addrTempRegister); - m_assembler.lw(dataTempRegister, addrTempRegister, 0); - if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767 - && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister); - } - m_assembler.sw(dataTempRegister, addrTempRegister, 0); - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.andInsn(dest, dest, src); - } - - void and32(Imm32 imm, RegisterID dest) - { - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - move(MIPSRegisters::zero, dest); - else if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535 - && !m_fixedWidth) - m_assembler.andi(dest, dest, imm.m_value); - else { - /* - li immTemp, imm - and dest, dest, immTemp - */ - move(imm, immTempRegister); - m_assembler.andInsn(dest, dest, immTempRegister); - } - } - - void lshift32(Imm32 imm, RegisterID dest) - { - m_assembler.sll(dest, dest, imm.m_value); - } - - void lshift32(RegisterID shiftAmount, RegisterID dest) - { - m_assembler.sllv(dest, dest, shiftAmount); - } - - void mul32(RegisterID src, RegisterID dest) - { - m_assembler.mul(dest, dest, src); - } - - void mul32(Imm32 imm, RegisterID src, RegisterID dest) - { - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - move(MIPSRegisters::zero, dest); - else if (!imm.m_isPointer && imm.m_value == 1 && !m_fixedWidth) - move(src, dest); - else { - /* - li dataTemp, imm - mul dest, src, dataTemp - */ - move(imm, dataTempRegister); - m_assembler.mul(dest, src, dataTempRegister); - } - } - - void neg32(RegisterID srcDest) - { - m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest); - } - - void not32(RegisterID srcDest) - { - m_assembler.nor(srcDest, srcDest, MIPSRegisters::zero); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orInsn(dest, dest, src); - } - - void or32(Imm32 imm, RegisterID dest) - { - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - return; - - if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535 - && !m_fixedWidth) { - m_assembler.ori(dest, dest, imm.m_value); - return; - } - - /* - li dataTemp, imm - or dest, dest, dataTemp - */ - move(imm, dataTempRegister); - m_assembler.orInsn(dest, dest, dataTempRegister); - } - - void rshift32(RegisterID shiftAmount, RegisterID dest) - { - m_assembler.srav(dest, dest, shiftAmount); - } - - void rshift32(Imm32 imm, RegisterID dest) - { - m_assembler.sra(dest, dest, imm.m_value); - } - - void urshift32(RegisterID shiftAmount, RegisterID dest) - { - m_assembler.srlv(dest, dest, shiftAmount); - } - - void urshift32(Imm32 imm, RegisterID dest) - { - m_assembler.srl(dest, dest, imm.m_value); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.subu(dest, dest, src); - } - - void sub32(Imm32 imm, RegisterID dest) - { - if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768 - && !m_fixedWidth) { - /* - addiu dest, src, imm - */ - m_assembler.addiu(dest, dest, -imm.m_value); - } else { - /* - li immTemp, imm - subu dest, src, immTemp - */ - move(imm, immTempRegister); - m_assembler.subu(dest, dest, immTempRegister); - } - } - - void sub32(Imm32 imm, Address address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - lw dataTemp, offset(base) - li immTemp, imm - subu dataTemp, dataTemp, immTemp - sw dataTemp, offset(base) - */ - m_assembler.lw(dataTempRegister, address.base, address.offset); - if (!imm.m_isPointer - && imm.m_value >= -32767 && imm.m_value <= 32768 - && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, - -imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.subu(dataTempRegister, dataTempRegister, - immTempRegister); - } - m_assembler.sw(dataTempRegister, address.base, address.offset); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lw dataTemp, (offset & 0xffff)(addrTemp) - li immtemp, imm - subu dataTemp, dataTemp, immTemp - sw dataTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dataTempRegister, addrTempRegister, address.offset); - - if (!imm.m_isPointer - && imm.m_value >= -32767 && imm.m_value <= 32768 - && !m_fixedWidth) - m_assembler.addiu(dataTempRegister, dataTempRegister, - -imm.m_value); - else { - move(imm, immTempRegister); - m_assembler.subu(dataTempRegister, dataTempRegister, - immTempRegister); - } - m_assembler.sw(dataTempRegister, addrTempRegister, address.offset); - } - } - - void sub32(Address src, RegisterID dest) - { - load32(src, dataTempRegister); - sub32(dataTempRegister, dest); - } - - void sub32(Imm32 imm, AbsoluteAddress address) - { - /* - li addrTemp, address - li immTemp, imm - lw dataTemp, 0(addrTemp) - subu dataTemp, dataTemp, immTemp - sw dataTemp, 0(addrTemp) - */ - move(ImmPtr(address.m_ptr), addrTempRegister); - m_assembler.lw(dataTempRegister, addrTempRegister, 0); - - if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768 - && !m_fixedWidth) { - m_assembler.addiu(dataTempRegister, dataTempRegister, - -imm.m_value); - } else { - move(imm, immTempRegister); - m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister); - } - m_assembler.sw(dataTempRegister, addrTempRegister, 0); - } - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.xorInsn(dest, dest, src); - } - - void xor32(Imm32 imm, RegisterID dest) - { - /* - li immTemp, imm - xor dest, dest, immTemp - */ - move(imm, immTempRegister); - m_assembler.xorInsn(dest, dest, immTempRegister); - } - - void sqrtDouble(FPRegisterID src, FPRegisterID dst) - { - m_assembler.sqrtd(dst, src); - } - - // Memory access operations: - // - // Loads are of the form load(address, destination) and stores of the form - // store(source, address). The source for a store may be an Imm32. Address - // operand objects to loads and store will be implicitly constructed if a - // register is passed. - - /* Need to use zero-extened load byte for load8. */ - void load8(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lbu(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lbu dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lbu(dest, addrTempRegister, address.offset); - } - } - - void load32(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lw(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lw dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dest, addrTempRegister, address.offset); - } - } - - void load32(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lw dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lw dest, (address.offset & 0xffff)(at) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lw(dest, addrTempRegister, address.offset); - } - } - - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32764 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - (Big-Endian) - lwl dest, address.offset(addrTemp) - lwr dest, address.offset+3(addrTemp) - (Little-Endian) - lwl dest, address.offset+3(addrTemp) - lwr dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); -#if CPU(BIG_ENDIAN) - m_assembler.lwl(dest, addrTempRegister, address.offset); - m_assembler.lwr(dest, addrTempRegister, address.offset + 3); -#else - m_assembler.lwl(dest, addrTempRegister, address.offset + 3); - m_assembler.lwr(dest, addrTempRegister, address.offset); - -#endif - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, address.offset >> 16 - ori immTemp, immTemp, address.offset & 0xffff - addu addrTemp, addrTemp, immTemp - (Big-Endian) - lw dest, 0(at) - lw dest, 3(at) - (Little-Endian) - lw dest, 3(at) - lw dest, 0(at) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, address.offset >> 16); - m_assembler.ori(immTempRegister, immTempRegister, address.offset); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); -#if CPU(BIG_ENDIAN) - m_assembler.lwl(dest, addrTempRegister, 0); - m_assembler.lwr(dest, addrTempRegister, 3); -#else - m_assembler.lwl(dest, addrTempRegister, 3); - m_assembler.lwr(dest, addrTempRegister, 0); -#endif - } - } - - void load32(void* address, RegisterID dest) - { - /* - li addrTemp, address - lw dest, 0(addrTemp) - */ - move(ImmPtr(address), addrTempRegister); - m_assembler.lw(dest, addrTempRegister, 0); - } - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - lw dest, 0(addrTemp) - */ - DataLabel32 dataLabel(this); - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dest, addrTempRegister, 0); - m_fixedWidth = false; - return dataLabel; - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - lw dest, 0(addrTemp) - */ - Label label(this); - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lw(dest, addrTempRegister, 0); - m_fixedWidth = false; - return label; - } - - /* Need to use zero-extened load half-word for load16. */ - void load16(ImplicitAddress address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.lhu(dest, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - lhu dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } - } - - /* Need to use zero-extened load half-word for load16. */ - void load16(BaseIndex address, RegisterID dest) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lhu dest, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - lhu dest, (address.offset & 0xffff)(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.lhu(dest, addrTempRegister, address.offset); - } - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - m_fixedWidth = true; - /* - lui addrTemp, address.offset >> 16 - ori addrTemp, addrTemp, address.offset & 0xffff - addu addrTemp, addrTemp, address.base - sw src, 0(addrTemp) - */ - DataLabel32 dataLabel(this); - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sw(src, addrTempRegister, 0); - m_fixedWidth = false; - return dataLabel; - } - - void store32(RegisterID src, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.sw(src, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sw src, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sw(src, addrTempRegister, address.offset); - } - } - - void store32(RegisterID src, BaseIndex address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - sw src, address.offset(addrTemp) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sw(src, addrTempRegister, address.offset); - } else { - /* - sll addrTemp, address.index, address.scale - addu addrTemp, addrTemp, address.base - lui immTemp, (address.offset + 0x8000) >> 16 - addu addrTemp, addrTemp, immTemp - sw src, (address.offset & 0xffff)(at) - */ - m_assembler.sll(addrTempRegister, address.index, address.scale); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, - immTempRegister); - m_assembler.sw(src, addrTempRegister, address.offset); - } - } - - void store32(Imm32 imm, ImplicitAddress address) - { - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - if (!imm.m_isPointer && !imm.m_value) - m_assembler.sw(MIPSRegisters::zero, address.base, - address.offset); - else { - move(imm, immTempRegister); - m_assembler.sw(immTempRegister, address.base, address.offset); - } - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sw immTemp, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - m_assembler.sw(MIPSRegisters::zero, addrTempRegister, - address.offset); - else { - move(imm, immTempRegister); - m_assembler.sw(immTempRegister, addrTempRegister, - address.offset); - } - } - } - - void store32(RegisterID src, void* address) - { - /* - li addrTemp, address - sw src, 0(addrTemp) - */ - move(ImmPtr(address), addrTempRegister); - m_assembler.sw(src, addrTempRegister, 0); - } - - void store32(Imm32 imm, void* address) - { - /* - li immTemp, imm - li addrTemp, address - sw src, 0(addrTemp) - */ - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) { - move(ImmPtr(address), addrTempRegister); - m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0); - } else { - move(imm, immTempRegister); - move(ImmPtr(address), addrTempRegister); - m_assembler.sw(immTempRegister, addrTempRegister, 0); - } - } - - // Floating-point operations: - - bool supportsFloatingPoint() const - { -#if WTF_MIPS_DOUBLE_FLOAT - return true; -#else - return false; -#endif - } - - bool supportsFloatingPointTruncate() const - { -#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2) - return true; -#else - return false; -#endif - } - - bool supportsFloatingPointSqrt() const - { -#if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2) - return true; -#else - return false; -#endif - } - - // Stack manipulation operations: - // - // The ABI is assumed to provide a stack abstraction to memory, - // containing machine word sized units of data. Push and pop - // operations add and remove a single register sized unit of data - // to or from the stack. Peek and poke operations read or write - // values on the stack, without moving the current stack position. - - void pop(RegisterID dest) - { - m_assembler.lw(dest, MIPSRegisters::sp, 0); - m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4); - } - - void push(RegisterID src) - { - m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4); - m_assembler.sw(src, MIPSRegisters::sp, 0); - } - - void push(Address address) - { - load32(address, dataTempRegister); - push(dataTempRegister); - } - - void push(Imm32 imm) - { - move(imm, immTempRegister); - push(immTempRegister); - } - - // Register move operations: - // - // Move values in registers. - - void move(Imm32 imm, RegisterID dest) - { - if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) - move(MIPSRegisters::zero, dest); - else if (imm.m_isPointer || m_fixedWidth) { - m_assembler.lui(dest, imm.m_value >> 16); - m_assembler.ori(dest, dest, imm.m_value); - } else - m_assembler.li(dest, imm.m_value); - } - - void move(RegisterID src, RegisterID dest) - { - if (src != dest || m_fixedWidth) - m_assembler.move(dest, src); - } - - void move(ImmPtr imm, RegisterID dest) - { - move(Imm32(imm), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - move(reg1, immTempRegister); - move(reg2, reg1); - move(immTempRegister, reg2); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest || m_fixedWidth) - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - if (src != dest || m_fixedWidth) - move(src, dest); - } - - // Forwards / external control flow operations: - // - // This set of jump and conditional branch operations return a Jump - // object which may linked at a later point, allow forwards jump, - // or jumps that will require external linkage (after the code has been - // relocated). - // - // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge - // respecitvely, for unsigned comparisons the names b, a, be, and ae are - // used (representing the names 'below' and 'above'). - // - // Operands to the comparision are provided in the expected order, e.g. - // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when - // treated as a signed 32bit value, is less than or equal to 5. - // - // jz and jnz test whether the first operand is equal to zero, and take - // an optional second operand of a mask under which to perform the test. - - Jump branch8(Condition cond, Address left, Imm32 right) - { - // Make sure the immediate value is unsigned 8 bits. - ASSERT(!(right.m_value & 0xFFFFFF00)); - load8(left, dataTempRegister); - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch32(Condition cond, RegisterID left, RegisterID right) - { - if (cond == Equal || cond == Zero) - return branchEqual(left, right); - if (cond == NotEqual || cond == NonZero) - return branchNotEqual(left, right); - if (cond == Above) { - m_assembler.sltu(cmpTempRegister, right, left); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == AboveOrEqual) { - m_assembler.sltu(cmpTempRegister, left, right); - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Below) { - m_assembler.sltu(cmpTempRegister, left, right); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == BelowOrEqual) { - m_assembler.sltu(cmpTempRegister, right, left); - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == GreaterThan) { - m_assembler.slt(cmpTempRegister, right, left); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == GreaterThanOrEqual) { - m_assembler.slt(cmpTempRegister, left, right); - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == LessThan) { - m_assembler.slt(cmpTempRegister, left, right); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == LessThanOrEqual) { - m_assembler.slt(cmpTempRegister, right, left); - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Overflow) { - /* - xor cmpTemp, left, right - bgez No_overflow, cmpTemp # same sign bit -> no overflow - nop - subu cmpTemp, left, right - xor cmpTemp, cmpTemp, left - bgez No_overflow, cmpTemp # same sign bit -> no overflow - nop - b Overflow - nop - nop - nop - nop - nop - No_overflow: - */ - m_assembler.xorInsn(cmpTempRegister, left, right); - m_assembler.bgez(cmpTempRegister, 11); - m_assembler.nop(); - m_assembler.subu(cmpTempRegister, left, right); - m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left); - m_assembler.bgez(cmpTempRegister, 7); - m_assembler.nop(); - return jump(); - } - if (cond == Signed) { - m_assembler.subu(cmpTempRegister, left, right); - // Check if the result is negative. - m_assembler.slt(cmpTempRegister, cmpTempRegister, - MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - ASSERT(0); - - return Jump(); - } - - Jump branch32(Condition cond, RegisterID left, Imm32 right) - { - move(right, immTempRegister); - return branch32(cond, left, immTempRegister); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - load32(right, dataTempRegister); - return branch32(cond, left, dataTempRegister); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - load32(left, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch32(Condition cond, Address left, Imm32 right) - { - load32(left, dataTempRegister); - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch32(Condition cond, BaseIndex left, Imm32 right) - { - load32(left, dataTempRegister); - // Be careful that the previous load32() uses immTempRegister. - // So, we need to put move() after load32(). - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) - { - load32WithUnalignedHalfWords(left, dataTempRegister); - // Be careful that the previous load32WithUnalignedHalfWords() - // uses immTempRegister. - // So, we need to put move() after load32WithUnalignedHalfWords(). - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - load32(left.m_ptr, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) - { - load32(left.m_ptr, dataTempRegister); - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - load16(left, dataTempRegister); - return branch32(cond, dataTempRegister, right); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) - { - ASSERT(!(right.m_value & 0xFFFF0000)); - load16(left, dataTempRegister); - // Be careful that the previous load16() uses immTempRegister. - // So, we need to put move() after load16(). - move(right, immTempRegister); - return branch32(cond, dataTempRegister, immTempRegister); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.andInsn(cmpTempRegister, reg, mask); - if (cond == Zero) - return branchEqual(cmpTempRegister, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1 && !m_fixedWidth) { - if (cond == Zero) - return branchEqual(reg, MIPSRegisters::zero); - return branchNotEqual(reg, MIPSRegisters::zero); - } - move(mask, immTempRegister); - return branchTest32(cond, reg, immTempRegister); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load32(address, dataTempRegister); - return branchTest32(cond, dataTempRegister, mask); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - load32(address, dataTempRegister); - return branchTest32(cond, dataTempRegister, mask); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - load8(address, dataTempRegister); - return branchTest32(cond, dataTempRegister, mask); - } - - Jump jump() - { - return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero); - } - - void jump(RegisterID target) - { - m_assembler.jr(target); - m_assembler.nop(); - } - - void jump(Address address) - { - m_fixedWidth = true; - load32(address, MIPSRegisters::t9); - m_assembler.jr(MIPSRegisters::t9); - m_assembler.nop(); - m_fixedWidth = false; - } - - // Arithmetic control flow operations: - // - // This set of conditional branch operations branch based - // on the result of an arithmetic operation. The operation - // is performed as normal, storing the result. - // - // * jz operations branch if the result is zero. - // * jo operations branch if the (signed) arithmetic - // operation caused an overflow to occur. - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - /* - move dest, dataTemp - xor cmpTemp, dataTemp, src - bltz cmpTemp, No_overflow # diff sign bit -> no overflow - addu dest, dataTemp, src - xor cmpTemp, dest, dataTemp - bgez cmpTemp, No_overflow # same sign big -> no overflow - nop - b Overflow - nop - nop - nop - nop - nop - No_overflow: - */ - move(dest, dataTempRegister); - m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src); - m_assembler.bltz(cmpTempRegister, 10); - m_assembler.addu(dest, dataTempRegister, src); - m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister); - m_assembler.bgez(cmpTempRegister, 7); - m_assembler.nop(); - return jump(); - } - if (cond == Signed) { - add32(src, dest); - // Check if dest is negative. - m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Zero) { - add32(src, dest); - return branchEqual(dest, MIPSRegisters::zero); - } - if (cond == NonZero) { - add32(src, dest); - return branchNotEqual(dest, MIPSRegisters::zero); - } - ASSERT(0); - return Jump(); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - move(imm, immTempRegister); - return branchAdd32(cond, immTempRegister, dest); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - /* - mult src, dest - mfhi dataTemp - mflo dest - sra addrTemp, dest, 31 - beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow - nop - b Overflow - nop - nop - nop - nop - nop - No_overflow: - */ - m_assembler.mult(src, dest); - m_assembler.mfhi(dataTempRegister); - m_assembler.mflo(dest); - m_assembler.sra(addrTempRegister, dest, 31); - m_assembler.beq(dataTempRegister, addrTempRegister, 7); - m_assembler.nop(); - return jump(); - } - if (cond == Signed) { - mul32(src, dest); - // Check if dest is negative. - m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Zero) { - mul32(src, dest); - return branchEqual(dest, MIPSRegisters::zero); - } - if (cond == NonZero) { - mul32(src, dest); - return branchNotEqual(dest, MIPSRegisters::zero); - } - ASSERT(0); - return Jump(); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - move(imm, immTempRegister); - move(src, dest); - return branchMul32(cond, immTempRegister, dest); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Overflow) { - /* - move dest, dataTemp - xor cmpTemp, dataTemp, src - bgez cmpTemp, No_overflow # same sign bit -> no overflow - subu dest, dataTemp, src - xor cmpTemp, dest, dataTemp - bgez cmpTemp, No_overflow # same sign bit -> no overflow - nop - b Overflow - nop - nop - nop - nop - nop - No_overflow: - */ - move(dest, dataTempRegister); - m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src); - m_assembler.bgez(cmpTempRegister, 10); - m_assembler.subu(dest, dataTempRegister, src); - m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister); - m_assembler.bgez(cmpTempRegister, 7); - m_assembler.nop(); - return jump(); - } - if (cond == Signed) { - sub32(src, dest); - // Check if dest is negative. - m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Zero) { - sub32(src, dest); - return branchEqual(dest, MIPSRegisters::zero); - } - if (cond == NonZero) { - sub32(src, dest); - return branchNotEqual(dest, MIPSRegisters::zero); - } - ASSERT(0); - return Jump(); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - move(imm, immTempRegister); - return branchSub32(cond, immTempRegister, dest); - } - - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); - if (cond == Signed) { - or32(src, dest); - // Check if dest is negative. - m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero); - return branchNotEqual(cmpTempRegister, MIPSRegisters::zero); - } - if (cond == Zero) { - or32(src, dest); - return branchEqual(dest, MIPSRegisters::zero); - } - if (cond == NonZero) { - or32(src, dest); - return branchNotEqual(dest, MIPSRegisters::zero); - } - ASSERT(0); - return Jump(); - } - - // Miscellaneous operations: - - void breakpoint() - { - m_assembler.bkpt(); - } - - Call nearCall() - { - /* We need two words for relaxation. */ - m_assembler.nop(); - m_assembler.nop(); - m_assembler.jal(); - m_assembler.nop(); - return Call(m_assembler.newJmpSrc(), Call::LinkableNear); - } - - Call call() - { - m_assembler.lui(MIPSRegisters::t9, 0); - m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0); - m_assembler.jalr(MIPSRegisters::t9); - m_assembler.nop(); - return Call(m_assembler.newJmpSrc(), Call::Linkable); - } - - Call call(RegisterID target) - { - m_assembler.jalr(target); - m_assembler.nop(); - return Call(m_assembler.newJmpSrc(), Call::None); - } - - Call call(Address address) - { - m_fixedWidth = true; - load32(address, MIPSRegisters::t9); - m_assembler.jalr(MIPSRegisters::t9); - m_assembler.nop(); - m_fixedWidth = false; - return Call(m_assembler.newJmpSrc(), Call::None); - } - - void ret() - { - m_assembler.jr(MIPSRegisters::ra); - m_assembler.nop(); - } - - void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - set32Compare32(cond, left, right, dest); - } - - void set8Compare32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - move(right, immTempRegister); - set32Compare32(cond, left, immTempRegister, dest); - } - - void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - if (cond == Equal || cond == Zero) { - m_assembler.xorInsn(dest, left, right); - m_assembler.sltiu(dest, dest, 1); - } else if (cond == NotEqual || cond == NonZero) { - m_assembler.xorInsn(dest, left, right); - m_assembler.sltu(dest, MIPSRegisters::zero, dest); - } else if (cond == Above) - m_assembler.sltu(dest, right, left); - else if (cond == AboveOrEqual) { - m_assembler.sltu(dest, left, right); - m_assembler.xori(dest, dest, 1); - } else if (cond == Below) - m_assembler.sltu(dest, left, right); - else if (cond == BelowOrEqual) { - m_assembler.sltu(dest, right, left); - m_assembler.xori(dest, dest, 1); - } else if (cond == GreaterThan) - m_assembler.slt(dest, right, left); - else if (cond == GreaterThanOrEqual) { - m_assembler.slt(dest, left, right); - m_assembler.xori(dest, dest, 1); - } else if (cond == LessThan) - m_assembler.slt(dest, left, right); - else if (cond == LessThanOrEqual) { - m_assembler.slt(dest, right, left); - m_assembler.xori(dest, dest, 1); - } else if (cond == Overflow) { - /* - xor cmpTemp, left, right - bgez Done, cmpTemp # same sign bit -> no overflow - move dest, 0 - subu cmpTemp, left, right - xor cmpTemp, cmpTemp, left # diff sign bit -> overflow - slt dest, cmpTemp, 0 - Done: - */ - m_assembler.xorInsn(cmpTempRegister, left, right); - m_assembler.bgez(cmpTempRegister, 4); - m_assembler.move(dest, MIPSRegisters::zero); - m_assembler.subu(cmpTempRegister, left, right); - m_assembler.xorInsn(cmpTempRegister, cmpTempRegister, left); - m_assembler.slt(dest, cmpTempRegister, MIPSRegisters::zero); - } else if (cond == Signed) { - m_assembler.subu(dest, left, right); - // Check if the result is negative. - m_assembler.slt(dest, dest, MIPSRegisters::zero); - } - } - - void set32Compare32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - move(right, immTempRegister); - set32Compare32(cond, left, immTempRegister, dest); - } - - void set32Test8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - ASSERT((cond == Zero) || (cond == NonZero)); - load8(address, dataTempRegister); - if (mask.m_value == -1 && !m_fixedWidth) { - if (cond == Zero) - m_assembler.sltiu(dest, dataTempRegister, 1); - else - m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister); - } else { - move(mask, immTempRegister); - m_assembler.andInsn(cmpTempRegister, dataTempRegister, - immTempRegister); - if (cond == Zero) - m_assembler.sltiu(dest, cmpTempRegister, 1); - else - m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister); - } - } - - void set32Test32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - ASSERT((cond == Zero) || (cond == NonZero)); - load32(address, dataTempRegister); - if (mask.m_value == -1 && !m_fixedWidth) { - if (cond == Zero) - m_assembler.sltiu(dest, dataTempRegister, 1); - else - m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister); - } else { - move(mask, immTempRegister); - m_assembler.andInsn(cmpTempRegister, dataTempRegister, - immTempRegister); - if (cond == Zero) - m_assembler.sltiu(dest, cmpTempRegister, 1); - else - m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister); - } - } - - DataLabel32 moveWithPatch(Imm32 imm, RegisterID dest) - { - m_fixedWidth = true; - DataLabel32 label(this); - move(imm, dest); - m_fixedWidth = false; - return label; - } - - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) - { - m_fixedWidth = true; - DataLabelPtr label(this); - move(initialValue, dest); - m_fixedWidth = false; - return label; - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - m_fixedWidth = true; - dataLabel = moveWithPatch(initialRightValue, immTempRegister); - Jump temp = branch32(cond, left, immTempRegister); - m_fixedWidth = false; - return temp; - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - m_fixedWidth = true; - load32(left, dataTempRegister); - dataLabel = moveWithPatch(initialRightValue, immTempRegister); - Jump temp = branch32(cond, dataTempRegister, immTempRegister); - m_fixedWidth = false; - return temp; - } - - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) - { - m_fixedWidth = true; - DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister); - store32(dataTempRegister, address); - m_fixedWidth = false; - return dataLabel; - } - - DataLabelPtr storePtrWithPatch(ImplicitAddress address) - { - return storePtrWithPatch(ImmPtr(0), address); - } - - Call tailRecursiveCall() - { - // Like a normal call, but don't update the returned address register - m_fixedWidth = true; - move(Imm32(0), MIPSRegisters::t9); - m_assembler.jr(MIPSRegisters::t9); - m_assembler.nop(); - m_fixedWidth = false; - return Call(m_assembler.newJmpSrc(), Call::Linkable); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - oldJump.link(this); - return tailRecursiveCall(); - } - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { -#if WTF_MIPS_ISA(1) - /* - li addrTemp, address.offset - addu addrTemp, addrTemp, base - lwc1 dest, 0(addrTemp) - lwc1 dest+1, 4(addrTemp) - */ - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.lwc1(dest, addrTempRegister, 0); - m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4); -#else - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) { - m_assembler.ldc1(dest, address.base, address.offset); - } else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - ldc1 dest, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.ldc1(dest, addrTempRegister, address.offset); - } -#endif - } - - void loadDouble(const void* address, FPRegisterID dest) - { -#if WTF_MIPS_ISA(1) - /* - li addrTemp, address - lwc1 dest, 0(addrTemp) - lwc1 dest+1, 4(addrTemp) - */ - move(ImmPtr(address), addrTempRegister); - m_assembler.lwc1(dest, addrTempRegister, 0); - m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4); -#else - /* - li addrTemp, address - ldc1 dest, 0(addrTemp) - */ - move(ImmPtr(address), addrTempRegister); - m_assembler.ldc1(dest, addrTempRegister, 0); -#endif - } - - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { -#if WTF_MIPS_ISA(1) - /* - li addrTemp, address.offset - addu addrTemp, addrTemp, base - swc1 dest, 0(addrTemp) - swc1 dest+1, 4(addrTemp) - */ - move(Imm32(address.offset), addrTempRegister); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.swc1(src, addrTempRegister, 0); - m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4); -#else - if (address.offset >= -32768 && address.offset <= 32767 - && !m_fixedWidth) - m_assembler.sdc1(src, address.base, address.offset); - else { - /* - lui addrTemp, (offset + 0x8000) >> 16 - addu addrTemp, addrTemp, base - sdc1 src, (offset & 0xffff)(addrTemp) - */ - m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16); - m_assembler.addu(addrTempRegister, addrTempRegister, address.base); - m_assembler.sdc1(src, addrTempRegister, address.offset); - } -#endif - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.addd(dest, dest, src); - } - - void addDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - m_assembler.addd(dest, dest, fpTempRegister); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.subd(dest, dest, src); - } - - void subDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - m_assembler.subd(dest, dest, fpTempRegister); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.muld(dest, dest, src); - } - - void mulDouble(Address src, FPRegisterID dest) - { - loadDouble(src, fpTempRegister); - m_assembler.muld(dest, dest, fpTempRegister); - } - - void divDouble(FPRegisterID src, FPRegisterID dest) - { - m_assembler.divd(dest, dest, src); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.mtc1(src, fpTempRegister); - m_assembler.cvtdw(dest, fpTempRegister); - } - - void convertInt32ToDouble(Address src, FPRegisterID dest) - { - load32(src, dataTempRegister); - m_assembler.mtc1(dataTempRegister, fpTempRegister); - m_assembler.cvtdw(dest, fpTempRegister); - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - load32(src.m_ptr, dataTempRegister); - m_assembler.mtc1(dataTempRegister, fpTempRegister); - m_assembler.cvtdw(dest, fpTempRegister); - } - - void insertRelaxationWords() - { - /* We need four words for relaxation. */ - m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops; - m_assembler.nop(); - m_assembler.nop(); - m_assembler.nop(); - } - - Jump branchTrue() - { - m_assembler.appendJump(); - m_assembler.bc1t(); - m_assembler.nop(); - insertRelaxationWords(); - return Jump(m_assembler.newJmpSrc()); - } - - Jump branchFalse() - { - m_assembler.appendJump(); - m_assembler.bc1f(); - m_assembler.nop(); - insertRelaxationWords(); - return Jump(m_assembler.newJmpSrc()); - } - - Jump branchEqual(RegisterID rs, RegisterID rt) - { - m_assembler.appendJump(); - m_assembler.beq(rs, rt, 0); - m_assembler.nop(); - insertRelaxationWords(); - return Jump(m_assembler.newJmpSrc()); - } - - Jump branchNotEqual(RegisterID rs, RegisterID rt) - { - m_assembler.appendJump(); - m_assembler.bne(rs, rt, 0); - m_assembler.nop(); - insertRelaxationWords(); - return Jump(m_assembler.newJmpSrc()); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - if (cond == DoubleEqual) { - m_assembler.ceqd(left, right); - return branchTrue(); - } - if (cond == DoubleNotEqual) { - m_assembler.cueqd(left, right); - return branchFalse(); // false - } - if (cond == DoubleGreaterThan) { - m_assembler.cngtd(left, right); - return branchFalse(); // false - } - if (cond == DoubleGreaterThanOrEqual) { - m_assembler.cnged(left, right); - return branchFalse(); // false - } - if (cond == DoubleLessThan) { - m_assembler.cltd(left, right); - return branchTrue(); - } - if (cond == DoubleLessThanOrEqual) { - m_assembler.cled(left, right); - return branchTrue(); - } - if (cond == DoubleEqualOrUnordered) { - m_assembler.cueqd(left, right); - return branchTrue(); - } - if (cond == DoubleNotEqualOrUnordered) { - m_assembler.ceqd(left, right); - return branchFalse(); // false - } - if (cond == DoubleGreaterThanOrUnordered) { - m_assembler.coled(left, right); - return branchFalse(); // false - } - if (cond == DoubleGreaterThanOrEqualOrUnordered) { - m_assembler.coltd(left, right); - return branchFalse(); // false - } - if (cond == DoubleLessThanOrUnordered) { - m_assembler.cultd(left, right); - return branchTrue(); - } - if (cond == DoubleLessThanOrEqualOrUnordered) { - m_assembler.culed(left, right); - return branchTrue(); - } - ASSERT(0); - - return Jump(); - } - - // Truncates 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, INT_MAX 0x7fffffff). - Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) - { - m_assembler.truncwd(fpTempRegister, src); - m_assembler.mfc1(dest, fpTempRegister); - return branch32(Equal, dest, Imm32(0x7fffffff)); - } - - // Convert 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) - { - m_assembler.cvtwd(fpTempRegister, src); - m_assembler.mfc1(dest, fpTempRegister); - - // If the result is zero, it might have been -0.0, and the double comparison won't catch this! - failureCases.append(branch32(Equal, dest, MIPSRegisters::zero)); - - // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - convertInt32ToDouble(dest, fpTemp); - failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src)); - } - - void zeroDouble(FPRegisterID dest) - { -#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64 - m_assembler.mtc1(MIPSRegisters::zero, dest); - m_assembler.mthc1(MIPSRegisters::zero, dest); -#else - m_assembler.mtc1(MIPSRegisters::zero, dest); - m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(dest + 1)); -#endif - } - -private: - // If m_fixedWidth is true, we will generate a fixed number of instructions. - // Otherwise, we can emit any number of instructions. - bool m_fixedWidth; - - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - MIPSAssembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - -}; - -} - -#endif // ENABLE(ASSEMBLER) && CPU(MIPS) - -#endif // MacroAssemblerMIPS_h diff --git a/JavaScriptCore/assembler/MacroAssemblerX86.h b/JavaScriptCore/assembler/MacroAssemblerX86.h deleted file mode 100644 index 0918996..0000000 --- a/JavaScriptCore/assembler/MacroAssemblerX86.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef MacroAssemblerX86_h -#define MacroAssemblerX86_h - -#if ENABLE(ASSEMBLER) && CPU(X86) - -#include "MacroAssemblerX86Common.h" - -namespace JSC { - -class MacroAssemblerX86 : public MacroAssemblerX86Common { -public: - MacroAssemblerX86() - : m_isSSE2Present(isSSE2Present()) - { - } - - static const Scale ScalePtr = TimesFour; - - using MacroAssemblerX86Common::add32; - using MacroAssemblerX86Common::and32; - using MacroAssemblerX86Common::sub32; - using MacroAssemblerX86Common::or32; - using MacroAssemblerX86Common::load32; - using MacroAssemblerX86Common::store32; - using MacroAssemblerX86Common::branch32; - using MacroAssemblerX86Common::call; - using MacroAssemblerX86Common::loadDouble; - using MacroAssemblerX86Common::convertInt32ToDouble; - - void add32(Imm32 imm, RegisterID src, RegisterID dest) - { - m_assembler.leal_mr(imm.m_value, src, dest); - } - - void add32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.addl_im(imm.m_value, address.m_ptr); - } - - void addWithCarry32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.adcl_im(imm.m_value, address.m_ptr); - } - - void and32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.andl_im(imm.m_value, address.m_ptr); - } - - void or32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.orl_im(imm.m_value, address.m_ptr); - } - - void sub32(Imm32 imm, AbsoluteAddress address) - { - m_assembler.subl_im(imm.m_value, address.m_ptr); - } - - void load32(void* address, RegisterID dest) - { - m_assembler.movl_mr(address, dest); - } - - void loadDouble(const void* address, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_mr(address, dest); - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - m_assembler.cvtsi2sd_mr(src.m_ptr, dest); - } - - void store32(Imm32 imm, void* address) - { - m_assembler.movl_i32m(imm.m_value, address); - } - - void store32(RegisterID src, void* address) - { - m_assembler.movl_rm(src, address); - } - - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) - { - m_assembler.cmpl_rm(right, left.m_ptr); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) - { - m_assembler.cmpl_im(right.m_value, left.m_ptr); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Call call() - { - return Call(m_assembler.call(), Call::Linkable); - } - - Call tailRecursiveCall() - { - return Call::fromTailJump(jump()); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - return Call::fromTailJump(oldJump); - } - - - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) - { - m_assembler.movl_i32r(initialValue.asIntptr(), dest); - return DataLabelPtr(this); - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - m_assembler.cmpl_ir_force32(initialRightValue.asIntptr(), left); - dataLabel = DataLabelPtr(this); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - m_assembler.cmpl_im_force32(initialRightValue.asIntptr(), left.offset, left.base); - dataLabel = DataLabelPtr(this); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) - { - m_assembler.movl_i32m(initialValue.asIntptr(), address.offset, address.base); - return DataLabelPtr(this); - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - load32(address, dest); - return label; - } - - bool supportsFloatingPoint() const { return m_isSSE2Present; } - // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() - bool supportsFloatingPointTruncate() const { return m_isSSE2Present; } - bool supportsFloatingPointSqrt() const { return m_isSSE2Present; } - -private: - const bool m_isSSE2Present; - - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - X86Assembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - X86Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); - } -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // MacroAssemblerX86_h diff --git a/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/JavaScriptCore/assembler/MacroAssemblerX86Common.h deleted file mode 100644 index b6f0b0c..0000000 --- a/JavaScriptCore/assembler/MacroAssemblerX86Common.h +++ /dev/null @@ -1,1085 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef MacroAssemblerX86Common_h -#define MacroAssemblerX86Common_h - -#if ENABLE(ASSEMBLER) - -#include "X86Assembler.h" -#include "AbstractMacroAssembler.h" - -namespace JSC { - -class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> { - static const int DoubleConditionBitInvert = 0x10; - static const int DoubleConditionBitSpecial = 0x20; - static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial; - -public: - typedef X86Assembler::FPRegisterID FPRegisterID; - - enum Condition { - Equal = X86Assembler::ConditionE, - NotEqual = X86Assembler::ConditionNE, - Above = X86Assembler::ConditionA, - AboveOrEqual = X86Assembler::ConditionAE, - Below = X86Assembler::ConditionB, - BelowOrEqual = X86Assembler::ConditionBE, - GreaterThan = X86Assembler::ConditionG, - GreaterThanOrEqual = X86Assembler::ConditionGE, - LessThan = X86Assembler::ConditionL, - LessThanOrEqual = X86Assembler::ConditionLE, - Overflow = X86Assembler::ConditionO, - Signed = X86Assembler::ConditionS, - Zero = X86Assembler::ConditionE, - NonZero = X86Assembler::ConditionNE - }; - - enum DoubleCondition { - // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. - DoubleEqual = X86Assembler::ConditionE | DoubleConditionBitSpecial, - DoubleNotEqual = X86Assembler::ConditionNE, - DoubleGreaterThan = X86Assembler::ConditionA, - DoubleGreaterThanOrEqual = X86Assembler::ConditionAE, - DoubleLessThan = X86Assembler::ConditionA | DoubleConditionBitInvert, - DoubleLessThanOrEqual = X86Assembler::ConditionAE | DoubleConditionBitInvert, - // If either operand is NaN, these conditions always evaluate to true. - DoubleEqualOrUnordered = X86Assembler::ConditionE, - DoubleNotEqualOrUnordered = X86Assembler::ConditionNE | DoubleConditionBitSpecial, - DoubleGreaterThanOrUnordered = X86Assembler::ConditionB | DoubleConditionBitInvert, - DoubleGreaterThanOrEqualOrUnordered = X86Assembler::ConditionBE | DoubleConditionBitInvert, - DoubleLessThanOrUnordered = X86Assembler::ConditionB, - DoubleLessThanOrEqualOrUnordered = X86Assembler::ConditionBE, - }; - COMPILE_ASSERT( - !((X86Assembler::ConditionE | X86Assembler::ConditionNE | X86Assembler::ConditionA | X86Assembler::ConditionAE | X86Assembler::ConditionB | X86Assembler::ConditionBE) & DoubleConditionBits), - DoubleConditionBits_should_not_interfere_with_X86Assembler_Condition_codes); - - static const RegisterID stackPointerRegister = X86Registers::esp; - - // Integer arithmetic operations: - // - // Operations are typically two operand - operation(source, srcDst) - // For many operations the source may be an Imm32, the srcDst operand - // may often be a memory location (explictly described using an Address - // object). - - void add32(RegisterID src, RegisterID dest) - { - m_assembler.addl_rr(src, dest); - } - - void add32(Imm32 imm, Address address) - { - m_assembler.addl_im(imm.m_value, address.offset, address.base); - } - - void add32(Imm32 imm, RegisterID dest) - { - m_assembler.addl_ir(imm.m_value, dest); - } - - void add32(Address src, RegisterID dest) - { - m_assembler.addl_mr(src.offset, src.base, dest); - } - - void add32(RegisterID src, Address dest) - { - m_assembler.addl_rm(src, dest.offset, dest.base); - } - - void and32(RegisterID src, RegisterID dest) - { - m_assembler.andl_rr(src, dest); - } - - void and32(Imm32 imm, RegisterID dest) - { - m_assembler.andl_ir(imm.m_value, dest); - } - - void and32(RegisterID src, Address dest) - { - m_assembler.andl_rm(src, dest.offset, dest.base); - } - - void and32(Address src, RegisterID dest) - { - m_assembler.andl_mr(src.offset, src.base, dest); - } - - void and32(Imm32 imm, Address address) - { - m_assembler.andl_im(imm.m_value, address.offset, address.base); - } - - void lshift32(Imm32 imm, RegisterID dest) - { - m_assembler.shll_i8r(imm.m_value, dest); - } - - void lshift32(RegisterID shift_amount, RegisterID dest) - { - // On x86 we can only shift by ecx; if asked to shift by another register we'll - // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86Registers::ecx) { - swap(shift_amount, X86Registers::ecx); - - // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" - if (dest == shift_amount) - m_assembler.shll_CLr(X86Registers::ecx); - // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86Registers::ecx) - m_assembler.shll_CLr(shift_amount); - // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" - else - m_assembler.shll_CLr(dest); - - swap(shift_amount, X86Registers::ecx); - } else - m_assembler.shll_CLr(dest); - } - - void mul32(RegisterID src, RegisterID dest) - { - m_assembler.imull_rr(src, dest); - } - - void mul32(Address src, RegisterID dest) - { - m_assembler.imull_mr(src.offset, src.base, dest); - } - - void mul32(Imm32 imm, RegisterID src, RegisterID dest) - { - m_assembler.imull_i32r(src, imm.m_value, dest); - } - - void neg32(RegisterID srcDest) - { - m_assembler.negl_r(srcDest); - } - - void neg32(Address srcDest) - { - m_assembler.negl_m(srcDest.offset, srcDest.base); - } - - void not32(RegisterID srcDest) - { - m_assembler.notl_r(srcDest); - } - - void not32(Address srcDest) - { - m_assembler.notl_m(srcDest.offset, srcDest.base); - } - - void or32(RegisterID src, RegisterID dest) - { - m_assembler.orl_rr(src, dest); - } - - void or32(Imm32 imm, RegisterID dest) - { - m_assembler.orl_ir(imm.m_value, dest); - } - - void or32(RegisterID src, Address dest) - { - m_assembler.orl_rm(src, dest.offset, dest.base); - } - - void or32(Address src, RegisterID dest) - { - m_assembler.orl_mr(src.offset, src.base, dest); - } - - void or32(Imm32 imm, Address address) - { - m_assembler.orl_im(imm.m_value, address.offset, address.base); - } - - void rshift32(RegisterID shift_amount, RegisterID dest) - { - // On x86 we can only shift by ecx; if asked to shift by another register we'll - // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86Registers::ecx) { - swap(shift_amount, X86Registers::ecx); - - // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" - if (dest == shift_amount) - m_assembler.sarl_CLr(X86Registers::ecx); - // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86Registers::ecx) - m_assembler.sarl_CLr(shift_amount); - // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" - else - m_assembler.sarl_CLr(dest); - - swap(shift_amount, X86Registers::ecx); - } else - m_assembler.sarl_CLr(dest); - } - - void rshift32(Imm32 imm, RegisterID dest) - { - m_assembler.sarl_i8r(imm.m_value, dest); - } - - void urshift32(RegisterID shift_amount, RegisterID dest) - { - // On x86 we can only shift by ecx; if asked to shift by another register we'll - // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86Registers::ecx) { - swap(shift_amount, X86Registers::ecx); - - // E.g. transform "shrl %eax, %eax" -> "xchgl %eax, %ecx; shrl %ecx, %ecx; xchgl %eax, %ecx" - if (dest == shift_amount) - m_assembler.shrl_CLr(X86Registers::ecx); - // E.g. transform "shrl %eax, %ecx" -> "xchgl %eax, %ecx; shrl %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86Registers::ecx) - m_assembler.shrl_CLr(shift_amount); - // E.g. transform "shrl %eax, %ebx" -> "xchgl %eax, %ecx; shrl %ecx, %ebx; xchgl %eax, %ecx" - else - m_assembler.shrl_CLr(dest); - - swap(shift_amount, X86Registers::ecx); - } else - m_assembler.shrl_CLr(dest); - } - - void urshift32(Imm32 imm, RegisterID dest) - { - m_assembler.shrl_i8r(imm.m_value, dest); - } - - void sub32(RegisterID src, RegisterID dest) - { - m_assembler.subl_rr(src, dest); - } - - void sub32(Imm32 imm, RegisterID dest) - { - m_assembler.subl_ir(imm.m_value, dest); - } - - void sub32(Imm32 imm, Address address) - { - m_assembler.subl_im(imm.m_value, address.offset, address.base); - } - - void sub32(Address src, RegisterID dest) - { - m_assembler.subl_mr(src.offset, src.base, dest); - } - - void sub32(RegisterID src, Address dest) - { - m_assembler.subl_rm(src, dest.offset, dest.base); - } - - - void xor32(RegisterID src, RegisterID dest) - { - m_assembler.xorl_rr(src, dest); - } - - void xor32(Imm32 imm, Address dest) - { - m_assembler.xorl_im(imm.m_value, dest.offset, dest.base); - } - - void xor32(Imm32 imm, RegisterID dest) - { - m_assembler.xorl_ir(imm.m_value, dest); - } - - void xor32(RegisterID src, Address dest) - { - m_assembler.xorl_rm(src, dest.offset, dest.base); - } - - void xor32(Address src, RegisterID dest) - { - m_assembler.xorl_mr(src.offset, src.base, dest); - } - - void sqrtDouble(FPRegisterID src, FPRegisterID dst) - { - m_assembler.sqrtsd_rr(src, dst); - } - - // Memory access operations: - // - // Loads are of the form load(address, destination) and stores of the form - // store(source, address). The source for a store may be an Imm32. Address - // operand objects to loads and store will be implicitly constructed if a - // register is passed. - - void load32(ImplicitAddress address, RegisterID dest) - { - m_assembler.movl_mr(address.offset, address.base, dest); - } - - void load32(BaseIndex address, RegisterID dest) - { - m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) - { - load32(address, dest); - } - - DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) - { - m_assembler.movl_mr_disp32(address.offset, address.base, dest); - return DataLabel32(this); - } - - void load16(BaseIndex address, RegisterID dest) - { - m_assembler.movzwl_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void load16(Address address, RegisterID dest) - { - m_assembler.movzwl_mr(address.offset, address.base, dest); - } - - DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) - { - m_assembler.movl_rm_disp32(src, address.offset, address.base); - return DataLabel32(this); - } - - void store32(RegisterID src, ImplicitAddress address) - { - m_assembler.movl_rm(src, address.offset, address.base); - } - - void store32(RegisterID src, BaseIndex address) - { - m_assembler.movl_rm(src, address.offset, address.base, address.index, address.scale); - } - - void store32(Imm32 imm, ImplicitAddress address) - { - m_assembler.movl_i32m(imm.m_value, address.offset, address.base); - } - - - // Floating-point operation: - // - // Presently only supports SSE, not x87 floating point. - - void loadDouble(ImplicitAddress address, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_mr(address.offset, address.base, dest); - } - - void storeDouble(FPRegisterID src, ImplicitAddress address) - { - ASSERT(isSSE2Present()); - m_assembler.movsd_rm(src, address.offset, address.base); - } - - void addDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.addsd_rr(src, dest); - } - - void addDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.addsd_mr(src.offset, src.base, dest); - } - - void divDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.divsd_rr(src, dest); - } - - void divDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.divsd_mr(src.offset, src.base, dest); - } - - void subDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.subsd_rr(src, dest); - } - - void subDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.subsd_mr(src.offset, src.base, dest); - } - - void mulDouble(FPRegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.mulsd_rr(src, dest); - } - - void mulDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.mulsd_mr(src.offset, src.base, dest); - } - - void convertInt32ToDouble(RegisterID src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.cvtsi2sd_rr(src, dest); - } - - void convertInt32ToDouble(Address src, FPRegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.cvtsi2sd_mr(src.offset, src.base, dest); - } - - Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) - { - ASSERT(isSSE2Present()); - - if (cond & DoubleConditionBitInvert) - m_assembler.ucomisd_rr(left, right); - else - m_assembler.ucomisd_rr(right, left); - - if (cond == DoubleEqual) { - Jump isUnordered(m_assembler.jp()); - Jump result = Jump(m_assembler.je()); - isUnordered.link(this); - return result; - } else if (cond == DoubleNotEqualOrUnordered) { - Jump isUnordered(m_assembler.jp()); - Jump isEqual(m_assembler.je()); - isUnordered.link(this); - Jump result = jump(); - isEqual.link(this); - return result; - } - - ASSERT(!(cond & DoubleConditionBitSpecial)); - return Jump(m_assembler.jCC(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits))); - } - - // Truncates 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, INT_MIN). - Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) - { - ASSERT(isSSE2Present()); - m_assembler.cvttsd2si_rr(src, dest); - return branch32(Equal, dest, Imm32(0x80000000)); - } - - // Convert 'src' to an integer, and places the resulting 'dest'. - // If the result is not representable as a 32 bit value, branch. - // May also branch for some values that are representable in 32 bits - // (specifically, in this case, 0). - void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) - { - ASSERT(isSSE2Present()); - m_assembler.cvttsd2si_rr(src, dest); - - // If the result is zero, it might have been -0.0, and the double comparison won't catch this! - failureCases.append(branchTest32(Zero, dest)); - - // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - convertInt32ToDouble(dest, fpTemp); - m_assembler.ucomisd_rr(fpTemp, src); - failureCases.append(m_assembler.jp()); - failureCases.append(m_assembler.jne()); - } - - void zeroDouble(FPRegisterID srcDest) - { - ASSERT(isSSE2Present()); - m_assembler.xorpd_rr(srcDest, srcDest); - } - - - // Stack manipulation operations: - // - // The ABI is assumed to provide a stack abstraction to memory, - // containing machine word sized units of data. Push and pop - // operations add and remove a single register sized unit of data - // to or from the stack. Peek and poke operations read or write - // values on the stack, without moving the current stack position. - - void pop(RegisterID dest) - { - m_assembler.pop_r(dest); - } - - void push(RegisterID src) - { - m_assembler.push_r(src); - } - - void push(Address address) - { - m_assembler.push_m(address.offset, address.base); - } - - void push(Imm32 imm) - { - m_assembler.push_i32(imm.m_value); - } - - - // Register move operations: - // - // Move values in registers. - - void move(Imm32 imm, RegisterID dest) - { - // Note: on 64-bit the Imm32 value is zero extended into the register, it - // may be useful to have a separate version that sign extends the value? - if (!imm.m_value) - m_assembler.xorl_rr(dest, dest); - else - m_assembler.movl_i32r(imm.m_value, dest); - } - -#if CPU(X86_64) - void move(RegisterID src, RegisterID dest) - { - // Note: on 64-bit this is is a full register move; perhaps it would be - // useful to have separate move32 & movePtr, with move32 zero extending? - if (src != dest) - m_assembler.movq_rr(src, dest); - } - - void move(ImmPtr imm, RegisterID dest) - { - m_assembler.movq_i64r(imm.asIntptr(), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - if (reg1 != reg2) - m_assembler.xchgq_rr(reg1, reg2); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - m_assembler.movsxd_rr(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - m_assembler.movl_rr(src, dest); - } -#else - void move(RegisterID src, RegisterID dest) - { - if (src != dest) - m_assembler.movl_rr(src, dest); - } - - void move(ImmPtr imm, RegisterID dest) - { - m_assembler.movl_i32r(imm.asIntptr(), dest); - } - - void swap(RegisterID reg1, RegisterID reg2) - { - if (reg1 != reg2) - m_assembler.xchgl_rr(reg1, reg2); - } - - void signExtend32ToPtr(RegisterID src, RegisterID dest) - { - move(src, dest); - } - - void zeroExtend32ToPtr(RegisterID src, RegisterID dest) - { - move(src, dest); - } -#endif - - - // Forwards / external control flow operations: - // - // This set of jump and conditional branch operations return a Jump - // object which may linked at a later point, allow forwards jump, - // or jumps that will require external linkage (after the code has been - // relocated). - // - // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge - // respecitvely, for unsigned comparisons the names b, a, be, and ae are - // used (representing the names 'below' and 'above'). - // - // Operands to the comparision are provided in the expected order, e.g. - // jle32(reg1, Imm32(5)) will branch if the value held in reg1, when - // treated as a signed 32bit value, is less than or equal to 5. - // - // jz and jnz test whether the first operand is equal to zero, and take - // an optional second operand of a mask under which to perform the test. - -public: - Jump branch8(Condition cond, Address left, Imm32 right) - { - m_assembler.cmpb_im(right.m_value, left.offset, left.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, RegisterID right) - { - m_assembler.cmpl_rr(right, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, Imm32 right) - { - if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) - m_assembler.testl_rr(left, left); - else - m_assembler.cmpl_ir(right.m_value, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, RegisterID left, Address right) - { - m_assembler.cmpl_mr(right.offset, right.base, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, Address left, RegisterID right) - { - m_assembler.cmpl_rm(right, left.offset, left.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, Address left, Imm32 right) - { - m_assembler.cmpl_im(right.m_value, left.offset, left.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32(Condition cond, BaseIndex left, Imm32 right) - { - m_assembler.cmpl_im(right.m_value, left.offset, left.base, left.index, left.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) - { - return branch32(cond, left, right); - } - - Jump branch16(Condition cond, BaseIndex left, RegisterID right) - { - m_assembler.cmpw_rm(right, left.offset, left.base, left.index, left.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) - { - ASSERT(!(right.m_value & 0xFFFF0000)); - - m_assembler.cmpw_im(right.m_value, left.offset, left.base, left.index, left.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) - { - ASSERT((cond == Zero) || (cond == NonZero)); - m_assembler.testl_rr(reg, mask); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - // if we are only interested in the low seven bits, this can be tested with a testb - if (mask.m_value == -1) - m_assembler.testl_rr(reg, reg); - else if ((mask.m_value & ~0x7f) == 0) - m_assembler.testb_i8r(mask.m_value, reg); - else - m_assembler.testl_i32r(mask.m_value, reg); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1) - m_assembler.cmpl_im(0, address.offset, address.base); - else - m_assembler.testl_i32m(mask.m_value, address.offset, address.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1) - m_assembler.cmpl_im(0, address.offset, address.base, address.index, address.scale); - else - m_assembler.testl_i32m(mask.m_value, address.offset, address.base, address.index, address.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1) - m_assembler.cmpb_im(0, address.offset, address.base); - else - m_assembler.testb_im(mask.m_value, address.offset, address.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTest8(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - ASSERT((cond == Zero) || (cond == NonZero)); - if (mask.m_value == -1) - m_assembler.cmpb_im(0, address.offset, address.base, address.index, address.scale); - else - m_assembler.testb_im(mask.m_value, address.offset, address.base, address.index, address.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump jump() - { - return Jump(m_assembler.jmp()); - } - - void jump(RegisterID target) - { - m_assembler.jmp_r(target); - } - - // Address is a memory location containing the address to jump to - void jump(Address address) - { - m_assembler.jmp_m(address.offset, address.base); - } - - - // Arithmetic control flow operations: - // - // This set of conditional branch operations branch based - // on the result of an arithmetic operation. The operation - // is performed as normal, storing the result. - // - // * jz operations branch if the result is zero. - // * jo operations branch if the (signed) arithmetic - // operation caused an overflow to occur. - - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - add32(imm, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchAdd32(Condition cond, Imm32 src, Address dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchAdd32(Condition cond, RegisterID src, Address dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchAdd32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - add32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT(cond == Overflow); - mul32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchMul32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - mul32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) - { - ASSERT(cond == Overflow); - mul32(imm, src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, Imm32 imm, Address dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - sub32(imm, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, RegisterID src, Address dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSub32(Condition cond, Address src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - sub32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchNeg32(Condition cond, RegisterID srcDest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - neg32(srcDest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); - or32(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - - // Miscellaneous operations: - - void breakpoint() - { - m_assembler.int3(); - } - - Call nearCall() - { - return Call(m_assembler.call(), Call::LinkableNear); - } - - Call call(RegisterID target) - { - return Call(m_assembler.call(target), Call::None); - } - - void call(Address address) - { - m_assembler.call_m(address.offset, address.base); - } - - void ret() - { - m_assembler.ret(); - } - - void set8Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmpl_rr(right, left); - m_assembler.setCC_r(x86Condition(cond), dest); - } - - void set8Compare32(Condition cond, Address left, RegisterID right, RegisterID dest) - { - m_assembler.cmpl_mr(left.offset, left.base, right); - m_assembler.setCC_r(x86Condition(cond), dest); - } - - void set8Compare32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) - m_assembler.testl_rr(left, left); - else - m_assembler.cmpl_ir(right.m_value, left); - m_assembler.setCC_r(x86Condition(cond), dest); - } - - void set32Compare32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - m_assembler.cmpl_rr(right, left); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void set32Compare32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) - m_assembler.testl_rr(left, left); - else - m_assembler.cmpl_ir(right.m_value, left); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - // FIXME: - // The mask should be optional... paerhaps the argument order should be - // dest-src, operations always have a dest? ... possibly not true, considering - // asm ops like test, or pseudo ops like pop(). - - void set32Test8(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - if (mask.m_value == -1) - m_assembler.cmpb_im(0, address.offset, address.base); - else - m_assembler.testb_im(mask.m_value, address.offset, address.base); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - void set32Test32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - if (mask.m_value == -1) - m_assembler.cmpl_im(0, address.offset, address.base); - else - m_assembler.testl_i32m(mask.m_value, address.offset, address.base); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - -protected: - X86Assembler::Condition x86Condition(Condition cond) - { - return static_cast<X86Assembler::Condition>(cond); - } - -private: - // Only MacroAssemblerX86 should be using the following method; SSE2 is always available on - // x86_64, and clients & subclasses of MacroAssembler should be using 'supportsFloatingPoint()'. - friend class MacroAssemblerX86; - -#if CPU(X86) -#if OS(MAC_OS_X) - - // All X86 Macs are guaranteed to support at least SSE2, - static bool isSSE2Present() - { - return true; - } - -#else // OS(MAC_OS_X) - - enum SSE2CheckState { - NotCheckedSSE2, - HasSSE2, - NoSSE2 - }; - - static bool isSSE2Present() - { - if (s_sse2CheckState == NotCheckedSSE2) { - // Default the flags value to zero; if the compiler is - // not MSVC or GCC we will read this as SSE2 not present. - int flags = 0; -#if COMPILER(MSVC) - _asm { - mov eax, 1 // cpuid function 1 gives us the standard feature set - cpuid; - mov flags, edx; - } -#elif COMPILER(GCC) - asm ( - "movl $0x1, %%eax;" - "pushl %%ebx;" - "cpuid;" - "popl %%ebx;" - "movl %%edx, %0;" - : "=g" (flags) - : - : "%eax", "%ecx", "%edx" - ); -#endif - static const int SSE2FeatureBit = 1 << 26; - s_sse2CheckState = (flags & SSE2FeatureBit) ? HasSSE2 : NoSSE2; - } - // Only check once. - ASSERT(s_sse2CheckState != NotCheckedSSE2); - - return s_sse2CheckState == HasSSE2; - } - - static SSE2CheckState s_sse2CheckState; - -#endif // OS(MAC_OS_X) -#elif !defined(NDEBUG) // CPU(X86) - - // On x86-64 we should never be checking for SSE2 in a non-debug build, - // but non debug add this method to keep the asserts above happy. - static bool isSSE2Present() - { - return true; - } - -#endif -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // MacroAssemblerX86Common_h diff --git a/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/JavaScriptCore/assembler/MacroAssemblerX86_64.h deleted file mode 100644 index 168c93f..0000000 --- a/JavaScriptCore/assembler/MacroAssemblerX86_64.h +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef MacroAssemblerX86_64_h -#define MacroAssemblerX86_64_h - -#if ENABLE(ASSEMBLER) && CPU(X86_64) - -#include "MacroAssemblerX86Common.h" - -#define REPTACH_OFFSET_CALL_R11 3 - -namespace JSC { - -class MacroAssemblerX86_64 : public MacroAssemblerX86Common { -protected: - static const X86Registers::RegisterID scratchRegister = X86Registers::r11; - -public: - static const Scale ScalePtr = TimesEight; - - using MacroAssemblerX86Common::add32; - using MacroAssemblerX86Common::and32; - using MacroAssemblerX86Common::or32; - using MacroAssemblerX86Common::sub32; - using MacroAssemblerX86Common::load32; - using MacroAssemblerX86Common::store32; - using MacroAssemblerX86Common::call; - using MacroAssemblerX86Common::loadDouble; - using MacroAssemblerX86Common::convertInt32ToDouble; - - void add32(Imm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - add32(imm, Address(scratchRegister)); - } - - void and32(Imm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - and32(imm, Address(scratchRegister)); - } - - void or32(Imm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - or32(imm, Address(scratchRegister)); - } - - void sub32(Imm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - sub32(imm, Address(scratchRegister)); - } - - void load32(void* address, RegisterID dest) - { - if (dest == X86Registers::eax) - m_assembler.movl_mEAX(address); - else { - move(X86Registers::eax, dest); - m_assembler.movl_mEAX(address); - swap(X86Registers::eax, dest); - } - } - - void loadDouble(const void* address, FPRegisterID dest) - { - move(ImmPtr(address), scratchRegister); - loadDouble(scratchRegister, dest); - } - - void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) - { - move(Imm32(*static_cast<int32_t*>(src.m_ptr)), scratchRegister); - m_assembler.cvtsi2sd_rr(scratchRegister, dest); - } - - void store32(Imm32 imm, void* address) - { - move(X86Registers::eax, scratchRegister); - move(imm, X86Registers::eax); - m_assembler.movl_EAXm(address); - move(scratchRegister, X86Registers::eax); - } - - Call call() - { - DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister); - Call result = Call(m_assembler.call(scratchRegister), Call::Linkable); - ASSERT(differenceBetween(label, result) == REPTACH_OFFSET_CALL_R11); - return result; - } - - Call tailRecursiveCall() - { - DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister); - Jump newJump = Jump(m_assembler.jmp_r(scratchRegister)); - ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11); - return Call::fromTailJump(newJump); - } - - Call makeTailRecursiveCall(Jump oldJump) - { - oldJump.link(this); - DataLabelPtr label = moveWithPatch(ImmPtr(0), scratchRegister); - Jump newJump = Jump(m_assembler.jmp_r(scratchRegister)); - ASSERT(differenceBetween(label, newJump) == REPTACH_OFFSET_CALL_R11); - return Call::fromTailJump(newJump); - } - - - void addPtr(RegisterID src, RegisterID dest) - { - m_assembler.addq_rr(src, dest); - } - - void addPtr(Imm32 imm, RegisterID srcDest) - { - m_assembler.addq_ir(imm.m_value, srcDest); - } - - void addPtr(ImmPtr imm, RegisterID dest) - { - move(imm, scratchRegister); - m_assembler.addq_rr(scratchRegister, dest); - } - - void addPtr(Imm32 imm, RegisterID src, RegisterID dest) - { - m_assembler.leaq_mr(imm.m_value, src, dest); - } - - void addPtr(Imm32 imm, Address address) - { - m_assembler.addq_im(imm.m_value, address.offset, address.base); - } - - void addPtr(Imm32 imm, AbsoluteAddress address) - { - move(ImmPtr(address.m_ptr), scratchRegister); - addPtr(imm, Address(scratchRegister)); - } - - void andPtr(RegisterID src, RegisterID dest) - { - m_assembler.andq_rr(src, dest); - } - - void andPtr(Imm32 imm, RegisterID srcDest) - { - m_assembler.andq_ir(imm.m_value, srcDest); - } - - void orPtr(RegisterID src, RegisterID dest) - { - m_assembler.orq_rr(src, dest); - } - - void orPtr(ImmPtr imm, RegisterID dest) - { - move(imm, scratchRegister); - m_assembler.orq_rr(scratchRegister, dest); - } - - void orPtr(Imm32 imm, RegisterID dest) - { - m_assembler.orq_ir(imm.m_value, dest); - } - - void subPtr(RegisterID src, RegisterID dest) - { - m_assembler.subq_rr(src, dest); - } - - void subPtr(Imm32 imm, RegisterID dest) - { - m_assembler.subq_ir(imm.m_value, dest); - } - - void subPtr(ImmPtr imm, RegisterID dest) - { - move(imm, scratchRegister); - m_assembler.subq_rr(scratchRegister, dest); - } - - void xorPtr(RegisterID src, RegisterID dest) - { - m_assembler.xorq_rr(src, dest); - } - - void xorPtr(Imm32 imm, RegisterID srcDest) - { - m_assembler.xorq_ir(imm.m_value, srcDest); - } - - - void loadPtr(ImplicitAddress address, RegisterID dest) - { - m_assembler.movq_mr(address.offset, address.base, dest); - } - - void loadPtr(BaseIndex address, RegisterID dest) - { - m_assembler.movq_mr(address.offset, address.base, address.index, address.scale, dest); - } - - void loadPtr(void* address, RegisterID dest) - { - if (dest == X86Registers::eax) - m_assembler.movq_mEAX(address); - else { - move(X86Registers::eax, dest); - m_assembler.movq_mEAX(address); - swap(X86Registers::eax, dest); - } - } - - DataLabel32 loadPtrWithAddressOffsetPatch(Address address, RegisterID dest) - { - m_assembler.movq_mr_disp32(address.offset, address.base, dest); - return DataLabel32(this); - } - - void storePtr(RegisterID src, ImplicitAddress address) - { - m_assembler.movq_rm(src, address.offset, address.base); - } - - void storePtr(RegisterID src, BaseIndex address) - { - m_assembler.movq_rm(src, address.offset, address.base, address.index, address.scale); - } - - void storePtr(RegisterID src, void* address) - { - if (src == X86Registers::eax) - m_assembler.movq_EAXm(address); - else { - swap(X86Registers::eax, src); - m_assembler.movq_EAXm(address); - swap(X86Registers::eax, src); - } - } - - void storePtr(ImmPtr imm, ImplicitAddress address) - { - move(imm, scratchRegister); - storePtr(scratchRegister, address); - } - - DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address) - { - m_assembler.movq_rm_disp32(src, address.offset, address.base); - return DataLabel32(this); - } - - void movePtrToDouble(RegisterID src, FPRegisterID dest) - { - m_assembler.movq_rr(src, dest); - } - - void moveDoubleToPtr(FPRegisterID src, RegisterID dest) - { - m_assembler.movq_rr(src, dest); - } - - void setPtr(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - if (((cond == Equal) || (cond == NotEqual)) && !right.m_value) - m_assembler.testq_rr(left, left); - else - m_assembler.cmpq_ir(right.m_value, left); - m_assembler.setCC_r(x86Condition(cond), dest); - m_assembler.movzbl_rr(dest, dest); - } - - Jump branchPtr(Condition cond, RegisterID left, RegisterID right) - { - m_assembler.cmpq_rr(right, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtr(Condition cond, RegisterID left, ImmPtr right) - { - move(right, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } - - Jump branchPtr(Condition cond, RegisterID left, Address right) - { - m_assembler.cmpq_mr(right.offset, right.base, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtr(Condition cond, AbsoluteAddress left, RegisterID right) - { - move(ImmPtr(left.m_ptr), scratchRegister); - return branchPtr(cond, Address(scratchRegister), right); - } - - Jump branchPtr(Condition cond, Address left, RegisterID right) - { - m_assembler.cmpq_rm(right, left.offset, left.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchPtr(Condition cond, Address left, ImmPtr right) - { - move(right, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } - - Jump branchTestPtr(Condition cond, RegisterID reg, RegisterID mask) - { - m_assembler.testq_rr(reg, mask); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTestPtr(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) - { - // if we are only interested in the low seven bits, this can be tested with a testb - if (mask.m_value == -1) - m_assembler.testq_rr(reg, reg); - else if ((mask.m_value & ~0x7f) == 0) - m_assembler.testb_i8r(mask.m_value, reg); - else - m_assembler.testq_i32r(mask.m_value, reg); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTestPtr(Condition cond, Address address, Imm32 mask = Imm32(-1)) - { - if (mask.m_value == -1) - m_assembler.cmpq_im(0, address.offset, address.base); - else - m_assembler.testq_i32m(mask.m_value, address.offset, address.base); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchTestPtr(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) - { - if (mask.m_value == -1) - m_assembler.cmpq_im(0, address.offset, address.base, address.index, address.scale); - else - m_assembler.testq_i32m(mask.m_value, address.offset, address.base, address.index, address.scale); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - - Jump branchAddPtr(Condition cond, RegisterID src, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - addPtr(src, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - Jump branchSubPtr(Condition cond, Imm32 imm, RegisterID dest) - { - ASSERT((cond == Overflow) || (cond == Zero) || (cond == NonZero)); - subPtr(imm, dest); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) - { - m_assembler.movq_i64r(initialValue.asIntptr(), dest); - return DataLabelPtr(this); - } - - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } - - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) - { - dataLabel = moveWithPatch(initialRightValue, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } - - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) - { - DataLabelPtr label = moveWithPatch(initialValue, scratchRegister); - storePtr(scratchRegister, address); - return label; - } - - using MacroAssemblerX86Common::branchTest8; - Jump branchTest8(Condition cond, ExtendedAddress address, Imm32 mask = Imm32(-1)) - { - ImmPtr addr(reinterpret_cast<void*>(address.offset)); - MacroAssemblerX86Common::move(addr, scratchRegister); - return MacroAssemblerX86Common::branchTest8(cond, BaseIndex(scratchRegister, address.base, TimesOne), mask); - } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) - { - Label label(this); - loadPtr(address, dest); - return label; - } - - bool supportsFloatingPoint() const { return true; } - // See comment on MacroAssemblerARMv7::supportsFloatingPointTruncate() - bool supportsFloatingPointTruncate() const { return true; } - bool supportsFloatingPointSqrt() const { return true; } - -private: - friend class LinkBuffer; - friend class RepatchBuffer; - - static void linkCall(void* code, Call call, FunctionPtr function) - { - if (!call.isFlagSet(Call::Near)) - X86Assembler::linkPointer(code, X86Assembler::labelFor(call.m_jmp, -REPTACH_OFFSET_CALL_R11), function.value()); - else - X86Assembler::linkCall(code, call.m_jmp, function.value()); - } - - static void repatchCall(CodeLocationCall call, CodeLocationLabel destination) - { - X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress()); - } - - static void repatchCall(CodeLocationCall call, FunctionPtr destination) - { - X86Assembler::repatchPointer(call.dataLabelPtrAtOffset(-REPTACH_OFFSET_CALL_R11).dataLocation(), destination.executableAddress()); - } - -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // MacroAssemblerX86_64_h diff --git a/JavaScriptCore/assembler/RepatchBuffer.h b/JavaScriptCore/assembler/RepatchBuffer.h deleted file mode 100644 index 72cf6b2..0000000 --- a/JavaScriptCore/assembler/RepatchBuffer.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2009 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef RepatchBuffer_h -#define RepatchBuffer_h - -#if ENABLE(ASSEMBLER) - -#include <MacroAssembler.h> -#include <wtf/Noncopyable.h> - -namespace JSC { - -// RepatchBuffer: -// -// This class is used to modify code after code generation has been completed, -// and after the code has potentially already been executed. This mechanism is -// used to apply optimizations to the code. -// -class RepatchBuffer { - typedef MacroAssemblerCodePtr CodePtr; - -public: - RepatchBuffer(CodeBlock* codeBlock) - { - JITCode& code = codeBlock->getJITCode(); - m_start = code.start(); - m_size = code.size(); - - ExecutableAllocator::makeWritable(m_start, m_size); - } - - ~RepatchBuffer() - { - ExecutableAllocator::makeExecutable(m_start, m_size); - } - - void relink(CodeLocationJump jump, CodeLocationLabel destination) - { - MacroAssembler::repatchJump(jump, destination); - } - - void relink(CodeLocationCall call, CodeLocationLabel destination) - { - MacroAssembler::repatchCall(call, destination); - } - - void relink(CodeLocationCall call, FunctionPtr destination) - { - MacroAssembler::repatchCall(call, destination); - } - - void relink(CodeLocationNearCall nearCall, CodePtr destination) - { - MacroAssembler::repatchNearCall(nearCall, CodeLocationLabel(destination)); - } - - void relink(CodeLocationNearCall nearCall, CodeLocationLabel destination) - { - MacroAssembler::repatchNearCall(nearCall, destination); - } - - void repatch(CodeLocationDataLabel32 dataLabel32, int32_t value) - { - MacroAssembler::repatchInt32(dataLabel32, value); - } - - void repatch(CodeLocationDataLabelPtr dataLabelPtr, void* value) - { - MacroAssembler::repatchPointer(dataLabelPtr, value); - } - - void repatchLoadPtrToLEA(CodeLocationInstruction instruction) - { - MacroAssembler::repatchLoadPtrToLEA(instruction); - } - - void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label) - { - relink(CodeLocationCall(CodePtr(returnAddress)), label); - } - - void relinkCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction) - { - relinkCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction)); - } - - void relinkCallerToFunction(ReturnAddressPtr returnAddress, FunctionPtr function) - { - relink(CodeLocationCall(CodePtr(returnAddress)), function); - } - - void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label) - { - relink(CodeLocationNearCall(CodePtr(returnAddress)), label); - } - - void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction) - { - relinkNearCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction)); - } - -private: - void* m_start; - size_t m_size; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) - -#endif // RepatchBuffer_h diff --git a/JavaScriptCore/assembler/X86Assembler.h b/JavaScriptCore/assembler/X86Assembler.h deleted file mode 100644 index b352ad4..0000000 --- a/JavaScriptCore/assembler/X86Assembler.h +++ /dev/null @@ -1,2100 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. - */ - -#ifndef X86Assembler_h -#define X86Assembler_h - -#if ENABLE(ASSEMBLER) && (CPU(X86) || CPU(X86_64)) - -#include "AssemblerBuffer.h" -#include <stdint.h> -#include <wtf/Assertions.h> -#include <wtf/Vector.h> - -namespace JSC { - -inline bool CAN_SIGN_EXTEND_8_32(int32_t value) { return value == (int32_t)(signed char)value; } - -namespace X86Registers { - typedef enum { - eax, - ecx, - edx, - ebx, - esp, - ebp, - esi, - edi, - -#if CPU(X86_64) - r8, - r9, - r10, - r11, - r12, - r13, - r14, - r15, -#endif - } RegisterID; - - typedef enum { - xmm0, - xmm1, - xmm2, - xmm3, - xmm4, - xmm5, - xmm6, - xmm7, - } XMMRegisterID; -} - -class X86Assembler { -public: - typedef X86Registers::RegisterID RegisterID; - typedef X86Registers::XMMRegisterID XMMRegisterID; - typedef XMMRegisterID FPRegisterID; - - typedef enum { - ConditionO, - ConditionNO, - ConditionB, - ConditionAE, - ConditionE, - ConditionNE, - ConditionBE, - ConditionA, - ConditionS, - ConditionNS, - ConditionP, - ConditionNP, - ConditionL, - ConditionGE, - ConditionLE, - ConditionG, - - ConditionC = ConditionB, - ConditionNC = ConditionAE, - } Condition; - -private: - typedef enum { - OP_ADD_EvGv = 0x01, - OP_ADD_GvEv = 0x03, - OP_OR_EvGv = 0x09, - OP_OR_GvEv = 0x0B, - OP_2BYTE_ESCAPE = 0x0F, - OP_AND_EvGv = 0x21, - OP_AND_GvEv = 0x23, - OP_SUB_EvGv = 0x29, - OP_SUB_GvEv = 0x2B, - PRE_PREDICT_BRANCH_NOT_TAKEN = 0x2E, - OP_XOR_EvGv = 0x31, - OP_XOR_GvEv = 0x33, - OP_CMP_EvGv = 0x39, - OP_CMP_GvEv = 0x3B, -#if CPU(X86_64) - PRE_REX = 0x40, -#endif - OP_PUSH_EAX = 0x50, - OP_POP_EAX = 0x58, -#if CPU(X86_64) - OP_MOVSXD_GvEv = 0x63, -#endif - PRE_OPERAND_SIZE = 0x66, - PRE_SSE_66 = 0x66, - OP_PUSH_Iz = 0x68, - OP_IMUL_GvEvIz = 0x69, - OP_GROUP1_EbIb = 0x80, - OP_GROUP1_EvIz = 0x81, - OP_GROUP1_EvIb = 0x83, - OP_TEST_EvGv = 0x85, - OP_XCHG_EvGv = 0x87, - OP_MOV_EvGv = 0x89, - OP_MOV_GvEv = 0x8B, - OP_LEA = 0x8D, - OP_GROUP1A_Ev = 0x8F, - OP_CDQ = 0x99, - OP_MOV_EAXOv = 0xA1, - OP_MOV_OvEAX = 0xA3, - OP_MOV_EAXIv = 0xB8, - OP_GROUP2_EvIb = 0xC1, - OP_RET = 0xC3, - OP_GROUP11_EvIz = 0xC7, - OP_INT3 = 0xCC, - OP_GROUP2_Ev1 = 0xD1, - OP_GROUP2_EvCL = 0xD3, - OP_CALL_rel32 = 0xE8, - OP_JMP_rel32 = 0xE9, - PRE_SSE_F2 = 0xF2, - OP_HLT = 0xF4, - OP_GROUP3_EbIb = 0xF6, - OP_GROUP3_Ev = 0xF7, - OP_GROUP3_EvIz = 0xF7, // OP_GROUP3_Ev has an immediate, when instruction is a test. - OP_GROUP5_Ev = 0xFF, - } OneByteOpcodeID; - - typedef enum { - OP2_MOVSD_VsdWsd = 0x10, - OP2_MOVSD_WsdVsd = 0x11, - OP2_CVTSI2SD_VsdEd = 0x2A, - OP2_CVTTSD2SI_GdWsd = 0x2C, - OP2_UCOMISD_VsdWsd = 0x2E, - OP2_ADDSD_VsdWsd = 0x58, - OP2_MULSD_VsdWsd = 0x59, - OP2_SUBSD_VsdWsd = 0x5C, - OP2_DIVSD_VsdWsd = 0x5E, - OP2_SQRTSD_VsdWsd = 0x51, - OP2_XORPD_VpdWpd = 0x57, - OP2_MOVD_VdEd = 0x6E, - OP2_MOVD_EdVd = 0x7E, - OP2_JCC_rel32 = 0x80, - OP_SETCC = 0x90, - OP2_IMUL_GvEv = 0xAF, - OP2_MOVZX_GvEb = 0xB6, - OP2_MOVZX_GvEw = 0xB7, - OP2_PEXTRW_GdUdIb = 0xC5, - } TwoByteOpcodeID; - - TwoByteOpcodeID jccRel32(Condition cond) - { - return (TwoByteOpcodeID)(OP2_JCC_rel32 + cond); - } - - TwoByteOpcodeID setccOpcode(Condition cond) - { - return (TwoByteOpcodeID)(OP_SETCC + cond); - } - - typedef enum { - GROUP1_OP_ADD = 0, - GROUP1_OP_OR = 1, - GROUP1_OP_ADC = 2, - GROUP1_OP_AND = 4, - GROUP1_OP_SUB = 5, - GROUP1_OP_XOR = 6, - GROUP1_OP_CMP = 7, - - GROUP1A_OP_POP = 0, - - GROUP2_OP_SHL = 4, - GROUP2_OP_SHR = 5, - GROUP2_OP_SAR = 7, - - GROUP3_OP_TEST = 0, - GROUP3_OP_NOT = 2, - GROUP3_OP_NEG = 3, - GROUP3_OP_IDIV = 7, - - GROUP5_OP_CALLN = 2, - GROUP5_OP_JMPN = 4, - GROUP5_OP_PUSH = 6, - - GROUP11_MOV = 0, - } GroupOpcodeID; - - class X86InstructionFormatter; -public: - - class JmpSrc { - friend class X86Assembler; - friend class X86InstructionFormatter; - public: - JmpSrc() - : m_offset(-1) - { - } - - private: - JmpSrc(int offset) - : m_offset(offset) - { - } - - int m_offset; - }; - - class JmpDst { - friend class X86Assembler; - friend class X86InstructionFormatter; - public: - JmpDst() - : m_offset(-1) - , m_used(false) - { - } - - bool isUsed() const { return m_used; } - bool isSet() const { return (m_offset != -1); } - void used() { m_used = true; } - private: - JmpDst(int offset) - : m_offset(offset) - , m_used(false) - { - ASSERT(m_offset == offset); - } - - int m_offset : 31; - bool m_used : 1; - }; - - X86Assembler() - { - } - - size_t size() const { return m_formatter.size(); } - - // Stack operations: - - void push_r(RegisterID reg) - { - m_formatter.oneByteOp(OP_PUSH_EAX, reg); - } - - void pop_r(RegisterID reg) - { - m_formatter.oneByteOp(OP_POP_EAX, reg); - } - - void push_i32(int imm) - { - m_formatter.oneByteOp(OP_PUSH_Iz); - m_formatter.immediate32(imm); - } - - void push_m(int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_PUSH, base, offset); - } - - void pop_m(int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP1A_Ev, GROUP1A_OP_POP, base, offset); - } - - // Arithmetic operations: - -#if !CPU(X86_64) - void adcl_im(int imm, void* addr) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADC, addr); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADC, addr); - m_formatter.immediate32(imm); - } - } -#endif - - void addl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_ADD_EvGv, src, dst); - } - - void addl_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp(OP_ADD_GvEv, dst, base, offset); - } - - void addl_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_ADD_EvGv, src, base, offset); - } - - void addl_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, dst); - m_formatter.immediate32(imm); - } - } - - void addl_im(int imm, int offset, RegisterID base) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, base, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, base, offset); - m_formatter.immediate32(imm); - } - } - -#if CPU(X86_64) - void addq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_ADD_EvGv, src, dst); - } - - void addq_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_ADD, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_ADD, dst); - m_formatter.immediate32(imm); - } - } - - void addq_im(int imm, int offset, RegisterID base) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_ADD, base, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_ADD, base, offset); - m_formatter.immediate32(imm); - } - } -#else - void addl_im(int imm, void* addr) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_ADD, addr); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_ADD, addr); - m_formatter.immediate32(imm); - } - } -#endif - - void andl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_AND_EvGv, src, dst); - } - - void andl_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp(OP_AND_GvEv, dst, base, offset); - } - - void andl_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_AND_EvGv, src, base, offset); - } - - void andl_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, dst); - m_formatter.immediate32(imm); - } - } - - void andl_im(int imm, int offset, RegisterID base) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, base, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, base, offset); - m_formatter.immediate32(imm); - } - } - -#if CPU(X86_64) - void andq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_AND_EvGv, src, dst); - } - - void andq_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_AND, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_AND, dst); - m_formatter.immediate32(imm); - } - } -#else - void andl_im(int imm, void* addr) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, addr); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, addr); - m_formatter.immediate32(imm); - } - } -#endif - - void negl_r(RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NEG, dst); - } - - void negl_m(int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NEG, base, offset); - } - - void notl_r(RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NOT, dst); - } - - void notl_m(int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_NOT, base, offset); - } - - void orl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_OR_EvGv, src, dst); - } - - void orl_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp(OP_OR_GvEv, dst, base, offset); - } - - void orl_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_OR_EvGv, src, base, offset); - } - - void orl_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, dst); - m_formatter.immediate32(imm); - } - } - - void orl_im(int imm, int offset, RegisterID base) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, base, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, base, offset); - m_formatter.immediate32(imm); - } - } - -#if CPU(X86_64) - void orq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_OR_EvGv, src, dst); - } - - void orq_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_OR, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_OR, dst); - m_formatter.immediate32(imm); - } - } -#else - void orl_im(int imm, void* addr) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, addr); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, addr); - m_formatter.immediate32(imm); - } - } -#endif - - void subl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_SUB_EvGv, src, dst); - } - - void subl_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp(OP_SUB_GvEv, dst, base, offset); - } - - void subl_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_SUB_EvGv, src, base, offset); - } - - void subl_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, dst); - m_formatter.immediate32(imm); - } - } - - void subl_im(int imm, int offset, RegisterID base) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, base, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, base, offset); - m_formatter.immediate32(imm); - } - } - -#if CPU(X86_64) - void subq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_SUB_EvGv, src, dst); - } - - void subq_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_SUB, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_SUB, dst); - m_formatter.immediate32(imm); - } - } -#else - void subl_im(int imm, void* addr) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_SUB, addr); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_SUB, addr); - m_formatter.immediate32(imm); - } - } -#endif - - void xorl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_XOR_EvGv, src, dst); - } - - void xorl_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp(OP_XOR_GvEv, dst, base, offset); - } - - void xorl_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_XOR_EvGv, src, base, offset); - } - - void xorl_im(int imm, int offset, RegisterID base) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_XOR, base, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_XOR, base, offset); - m_formatter.immediate32(imm); - } - } - - void xorl_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_XOR, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_XOR, dst); - m_formatter.immediate32(imm); - } - } - -#if CPU(X86_64) - void xorq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_XOR_EvGv, src, dst); - } - - void xorq_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_XOR, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_XOR, dst); - m_formatter.immediate32(imm); - } - } -#endif - - void sarl_i8r(int imm, RegisterID dst) - { - if (imm == 1) - m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst); - else { - m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst); - m_formatter.immediate8(imm); - } - } - - void sarl_CLr(RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); - } - - void shrl_i8r(int imm, RegisterID dst) - { - if (imm == 1) - m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst); - else { - m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst); - m_formatter.immediate8(imm); - } - } - - void shrl_CLr(RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst); - } - - void shll_i8r(int imm, RegisterID dst) - { - if (imm == 1) - m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst); - else { - m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst); - m_formatter.immediate8(imm); - } - } - - void shll_CLr(RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst); - } - -#if CPU(X86_64) - void sarq_CLr(RegisterID dst) - { - m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst); - } - - void sarq_i8r(int imm, RegisterID dst) - { - if (imm == 1) - m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst); - else { - m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst); - m_formatter.immediate8(imm); - } - } -#endif - - void imull_rr(RegisterID src, RegisterID dst) - { - m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src); - } - - void imull_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, base, offset); - } - - void imull_i32r(RegisterID src, int32_t value, RegisterID dst) - { - m_formatter.oneByteOp(OP_IMUL_GvEvIz, dst, src); - m_formatter.immediate32(value); - } - - void idivl_r(RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_IDIV, dst); - } - - // Comparisons: - - void cmpl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_CMP_EvGv, src, dst); - } - - void cmpl_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_CMP_EvGv, src, base, offset); - } - - void cmpl_mr(int offset, RegisterID base, RegisterID src) - { - m_formatter.oneByteOp(OP_CMP_GvEv, src, base, offset); - } - - void cmpl_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst); - m_formatter.immediate32(imm); - } - } - - void cmpl_ir_force32(int imm, RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst); - m_formatter.immediate32(imm); - } - - void cmpl_im(int imm, int offset, RegisterID base) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset); - m_formatter.immediate32(imm); - } - } - - void cmpb_im(int imm, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, offset); - m_formatter.immediate8(imm); - } - - void cmpb_im(int imm, int offset, RegisterID base, RegisterID index, int scale) - { - m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, index, scale, offset); - m_formatter.immediate8(imm); - } - - void cmpl_im(int imm, int offset, RegisterID base, RegisterID index, int scale) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset); - m_formatter.immediate32(imm); - } - } - - void cmpl_im_force32(int imm, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset); - m_formatter.immediate32(imm); - } - -#if CPU(X86_64) - void cmpq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_CMP_EvGv, src, dst); - } - - void cmpq_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp64(OP_CMP_EvGv, src, base, offset); - } - - void cmpq_mr(int offset, RegisterID base, RegisterID src) - { - m_formatter.oneByteOp64(OP_CMP_GvEv, src, base, offset); - } - - void cmpq_ir(int imm, RegisterID dst) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, dst); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst); - m_formatter.immediate32(imm); - } - } - - void cmpq_im(int imm, int offset, RegisterID base) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, offset); - m_formatter.immediate32(imm); - } - } - - void cmpq_im(int imm, int offset, RegisterID base, RegisterID index, int scale) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset); - m_formatter.immediate32(imm); - } - } -#else - void cmpl_rm(RegisterID reg, void* addr) - { - m_formatter.oneByteOp(OP_CMP_EvGv, reg, addr); - } - - void cmpl_im(int imm, void* addr) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, addr); - m_formatter.immediate8(imm); - } else { - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, addr); - m_formatter.immediate32(imm); - } - } -#endif - - void cmpw_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale) - { - m_formatter.prefix(PRE_OPERAND_SIZE); - m_formatter.oneByteOp(OP_CMP_EvGv, src, base, index, scale, offset); - } - - void cmpw_im(int imm, int offset, RegisterID base, RegisterID index, int scale) - { - if (CAN_SIGN_EXTEND_8_32(imm)) { - m_formatter.prefix(PRE_OPERAND_SIZE); - m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_CMP, base, index, scale, offset); - m_formatter.immediate8(imm); - } else { - m_formatter.prefix(PRE_OPERAND_SIZE); - m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, base, index, scale, offset); - m_formatter.immediate16(imm); - } - } - - void testl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_TEST_EvGv, src, dst); - } - - void testl_i32r(int imm, RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, dst); - m_formatter.immediate32(imm); - } - - void testl_i32m(int imm, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, offset); - m_formatter.immediate32(imm); - } - - void testb_im(int imm, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, offset); - m_formatter.immediate8(imm); - } - - void testb_im(int imm, int offset, RegisterID base, RegisterID index, int scale) - { - m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, index, scale, offset); - m_formatter.immediate8(imm); - } - - void testl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale) - { - m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset); - m_formatter.immediate32(imm); - } - -#if CPU(X86_64) - void testq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_TEST_EvGv, src, dst); - } - - void testq_i32r(int imm, RegisterID dst) - { - m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, dst); - m_formatter.immediate32(imm); - } - - void testq_i32m(int imm, int offset, RegisterID base) - { - m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, offset); - m_formatter.immediate32(imm); - } - - void testq_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale) - { - m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset); - m_formatter.immediate32(imm); - } -#endif - - void testw_rr(RegisterID src, RegisterID dst) - { - m_formatter.prefix(PRE_OPERAND_SIZE); - m_formatter.oneByteOp(OP_TEST_EvGv, src, dst); - } - - void testb_i8r(int imm, RegisterID dst) - { - m_formatter.oneByteOp8(OP_GROUP3_EbIb, GROUP3_OP_TEST, dst); - m_formatter.immediate8(imm); - } - - void setCC_r(Condition cond, RegisterID dst) - { - m_formatter.twoByteOp8(setccOpcode(cond), (GroupOpcodeID)0, dst); - } - - void sete_r(RegisterID dst) - { - m_formatter.twoByteOp8(setccOpcode(ConditionE), (GroupOpcodeID)0, dst); - } - - void setz_r(RegisterID dst) - { - sete_r(dst); - } - - void setne_r(RegisterID dst) - { - m_formatter.twoByteOp8(setccOpcode(ConditionNE), (GroupOpcodeID)0, dst); - } - - void setnz_r(RegisterID dst) - { - setne_r(dst); - } - - // Various move ops: - - void cdq() - { - m_formatter.oneByteOp(OP_CDQ); - } - - void xchgl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_XCHG_EvGv, src, dst); - } - -#if CPU(X86_64) - void xchgq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_XCHG_EvGv, src, dst); - } -#endif - - void movl_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp(OP_MOV_EvGv, src, dst); - } - - void movl_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_MOV_EvGv, src, base, offset); - } - - void movl_rm_disp32(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp_disp32(OP_MOV_EvGv, src, base, offset); - } - - void movl_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale) - { - m_formatter.oneByteOp(OP_MOV_EvGv, src, base, index, scale, offset); - } - - void movl_mEAX(void* addr) - { - m_formatter.oneByteOp(OP_MOV_EAXOv); -#if CPU(X86_64) - m_formatter.immediate64(reinterpret_cast<int64_t>(addr)); -#else - m_formatter.immediate32(reinterpret_cast<int>(addr)); -#endif - } - - void movl_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, offset); - } - - void movl_mr_disp32(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, base, offset); - } - - void movl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) - { - m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, index, scale, offset); - } - - void movl_i32r(int imm, RegisterID dst) - { - m_formatter.oneByteOp(OP_MOV_EAXIv, dst); - m_formatter.immediate32(imm); - } - - void movl_i32m(int imm, int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, offset); - m_formatter.immediate32(imm); - } - - void movl_EAXm(void* addr) - { - m_formatter.oneByteOp(OP_MOV_OvEAX); -#if CPU(X86_64) - m_formatter.immediate64(reinterpret_cast<int64_t>(addr)); -#else - m_formatter.immediate32(reinterpret_cast<int>(addr)); -#endif - } - -#if CPU(X86_64) - void movq_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_MOV_EvGv, src, dst); - } - - void movq_rm(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, offset); - } - - void movq_rm_disp32(RegisterID src, int offset, RegisterID base) - { - m_formatter.oneByteOp64_disp32(OP_MOV_EvGv, src, base, offset); - } - - void movq_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale) - { - m_formatter.oneByteOp64(OP_MOV_EvGv, src, base, index, scale, offset); - } - - void movq_mEAX(void* addr) - { - m_formatter.oneByteOp64(OP_MOV_EAXOv); - m_formatter.immediate64(reinterpret_cast<int64_t>(addr)); - } - - void movq_EAXm(void* addr) - { - m_formatter.oneByteOp64(OP_MOV_OvEAX); - m_formatter.immediate64(reinterpret_cast<int64_t>(addr)); - } - - void movq_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, offset); - } - - void movq_mr_disp32(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp64_disp32(OP_MOV_GvEv, dst, base, offset); - } - - void movq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) - { - m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, index, scale, offset); - } - - void movq_i32m(int imm, int offset, RegisterID base) - { - m_formatter.oneByteOp64(OP_GROUP11_EvIz, GROUP11_MOV, base, offset); - m_formatter.immediate32(imm); - } - - void movq_i64r(int64_t imm, RegisterID dst) - { - m_formatter.oneByteOp64(OP_MOV_EAXIv, dst); - m_formatter.immediate64(imm); - } - - void movsxd_rr(RegisterID src, RegisterID dst) - { - m_formatter.oneByteOp64(OP_MOVSXD_GvEv, dst, src); - } - - -#else - void movl_rm(RegisterID src, void* addr) - { - if (src == X86Registers::eax) - movl_EAXm(addr); - else - m_formatter.oneByteOp(OP_MOV_EvGv, src, addr); - } - - void movl_mr(void* addr, RegisterID dst) - { - if (dst == X86Registers::eax) - movl_mEAX(addr); - else - m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr); - } - - void movl_i32m(int imm, void* addr) - { - m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, addr); - m_formatter.immediate32(imm); - } -#endif - - void movzwl_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.twoByteOp(OP2_MOVZX_GvEw, dst, base, offset); - } - - void movzwl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst) - { - m_formatter.twoByteOp(OP2_MOVZX_GvEw, dst, base, index, scale, offset); - } - - void movzbl_rr(RegisterID src, RegisterID dst) - { - // In 64-bit, this may cause an unnecessary REX to be planted (if the dst register - // is in the range ESP-EDI, and the src would not have required a REX). Unneeded - // REX prefixes are defined to be silently ignored by the processor. - m_formatter.twoByteOp8(OP2_MOVZX_GvEb, dst, src); - } - - void leal_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp(OP_LEA, dst, base, offset); - } -#if CPU(X86_64) - void leaq_mr(int offset, RegisterID base, RegisterID dst) - { - m_formatter.oneByteOp64(OP_LEA, dst, base, offset); - } -#endif - - // Flow control: - - JmpSrc call() - { - m_formatter.oneByteOp(OP_CALL_rel32); - return m_formatter.immediateRel32(); - } - - JmpSrc call(RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, dst); - return JmpSrc(m_formatter.size()); - } - - void call_m(int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, base, offset); - } - - JmpSrc jmp() - { - m_formatter.oneByteOp(OP_JMP_rel32); - return m_formatter.immediateRel32(); - } - - // Return a JmpSrc so we have a label to the jump, so we can use this - // To make a tail recursive call on x86-64. The MacroAssembler - // really shouldn't wrap this as a Jump, since it can't be linked. :-/ - JmpSrc jmp_r(RegisterID dst) - { - m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, dst); - return JmpSrc(m_formatter.size()); - } - - void jmp_m(int offset, RegisterID base) - { - m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, base, offset); - } - - JmpSrc jne() - { - m_formatter.twoByteOp(jccRel32(ConditionNE)); - return m_formatter.immediateRel32(); - } - - JmpSrc jnz() - { - return jne(); - } - - JmpSrc je() - { - m_formatter.twoByteOp(jccRel32(ConditionE)); - return m_formatter.immediateRel32(); - } - - JmpSrc jz() - { - return je(); - } - - JmpSrc jl() - { - m_formatter.twoByteOp(jccRel32(ConditionL)); - return m_formatter.immediateRel32(); - } - - JmpSrc jb() - { - m_formatter.twoByteOp(jccRel32(ConditionB)); - return m_formatter.immediateRel32(); - } - - JmpSrc jle() - { - m_formatter.twoByteOp(jccRel32(ConditionLE)); - return m_formatter.immediateRel32(); - } - - JmpSrc jbe() - { - m_formatter.twoByteOp(jccRel32(ConditionBE)); - return m_formatter.immediateRel32(); - } - - JmpSrc jge() - { - m_formatter.twoByteOp(jccRel32(ConditionGE)); - return m_formatter.immediateRel32(); - } - - JmpSrc jg() - { - m_formatter.twoByteOp(jccRel32(ConditionG)); - return m_formatter.immediateRel32(); - } - - JmpSrc ja() - { - m_formatter.twoByteOp(jccRel32(ConditionA)); - return m_formatter.immediateRel32(); - } - - JmpSrc jae() - { - m_formatter.twoByteOp(jccRel32(ConditionAE)); - return m_formatter.immediateRel32(); - } - - JmpSrc jo() - { - m_formatter.twoByteOp(jccRel32(ConditionO)); - return m_formatter.immediateRel32(); - } - - JmpSrc jp() - { - m_formatter.twoByteOp(jccRel32(ConditionP)); - return m_formatter.immediateRel32(); - } - - JmpSrc js() - { - m_formatter.twoByteOp(jccRel32(ConditionS)); - return m_formatter.immediateRel32(); - } - - JmpSrc jCC(Condition cond) - { - m_formatter.twoByteOp(jccRel32(cond)); - return m_formatter.immediateRel32(); - } - - // SSE operations: - - void addsd_rr(XMMRegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, (RegisterID)src); - } - - void addsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)dst, base, offset); - } - - void cvtsi2sd_rr(RegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, src); - } - - void cvtsi2sd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, base, offset); - } - -#if !CPU(X86_64) - void cvtsi2sd_mr(void* address, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_CVTSI2SD_VsdEd, (RegisterID)dst, address); - } -#endif - - void cvttsd2si_rr(XMMRegisterID src, RegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_CVTTSD2SI_GdWsd, dst, (RegisterID)src); - } - - void movd_rr(XMMRegisterID src, RegisterID dst) - { - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteOp(OP2_MOVD_EdVd, (RegisterID)src, dst); - } - -#if CPU(X86_64) - void movq_rr(XMMRegisterID src, RegisterID dst) - { - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteOp64(OP2_MOVD_EdVd, (RegisterID)src, dst); - } - - void movq_rr(RegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteOp64(OP2_MOVD_VdEd, (RegisterID)dst, src); - } -#endif - - void movsd_rm(XMMRegisterID src, int offset, RegisterID base) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, offset); - } - - void movsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, base, offset); - } - -#if !CPU(X86_64) - void movsd_mr(const void* address, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, address); - } -#endif - - void mulsd_rr(XMMRegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_MULSD_VsdWsd, (RegisterID)dst, (RegisterID)src); - } - - void mulsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_MULSD_VsdWsd, (RegisterID)dst, base, offset); - } - - void pextrw_irr(int whichWord, XMMRegisterID src, RegisterID dst) - { - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteOp(OP2_PEXTRW_GdUdIb, (RegisterID)dst, (RegisterID)src); - m_formatter.immediate8(whichWord); - } - - void subsd_rr(XMMRegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, (RegisterID)dst, (RegisterID)src); - } - - void subsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, (RegisterID)dst, base, offset); - } - - void ucomisd_rr(XMMRegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteOp(OP2_UCOMISD_VsdWsd, (RegisterID)dst, (RegisterID)src); - } - - void ucomisd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteOp(OP2_UCOMISD_VsdWsd, (RegisterID)dst, base, offset); - } - - void divsd_rr(XMMRegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)dst, (RegisterID)src); - } - - void divsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)dst, base, offset); - } - - void xorpd_rr(XMMRegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_66); - m_formatter.twoByteOp(OP2_XORPD_VpdWpd, (RegisterID)dst, (RegisterID)src); - } - - void sqrtsd_rr(XMMRegisterID src, XMMRegisterID dst) - { - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_SQRTSD_VsdWsd, (RegisterID)dst, (RegisterID)src); - } - - // Misc instructions: - - void int3() - { - m_formatter.oneByteOp(OP_INT3); - } - - void ret() - { - m_formatter.oneByteOp(OP_RET); - } - - void predictNotTaken() - { - m_formatter.prefix(PRE_PREDICT_BRANCH_NOT_TAKEN); - } - - // Assembler admin methods: - - JmpDst label() - { - return JmpDst(m_formatter.size()); - } - - static JmpDst labelFor(JmpSrc jump, intptr_t offset = 0) - { - return JmpDst(jump.m_offset + offset); - } - - JmpDst align(int alignment) - { - while (!m_formatter.isAligned(alignment)) - m_formatter.oneByteOp(OP_HLT); - - return label(); - } - - // Linking & patching: - // - // 'link' and 'patch' methods are for use on unprotected code - such as the code - // within the AssemblerBuffer, and code being patched by the patch buffer. Once - // code has been finalized it is (platform support permitting) within a non- - // writable region of memory; to modify the code in an execute-only execuable - // pool the 'repatch' and 'relink' methods should be used. - - void linkJump(JmpSrc from, JmpDst to) - { - ASSERT(from.m_offset != -1); - ASSERT(to.m_offset != -1); - - char* code = reinterpret_cast<char*>(m_formatter.data()); - setRel32(code + from.m_offset, code + to.m_offset); - } - - static void linkJump(void* code, JmpSrc from, void* to) - { - ASSERT(from.m_offset != -1); - - setRel32(reinterpret_cast<char*>(code) + from.m_offset, to); - } - - static void linkCall(void* code, JmpSrc from, void* to) - { - ASSERT(from.m_offset != -1); - - setRel32(reinterpret_cast<char*>(code) + from.m_offset, to); - } - - static void linkPointer(void* code, JmpDst where, void* value) - { - ASSERT(where.m_offset != -1); - - setPointer(reinterpret_cast<char*>(code) + where.m_offset, value); - } - - static void relinkJump(void* from, void* to) - { - setRel32(from, to); - } - - static void relinkCall(void* from, void* to) - { - setRel32(from, to); - } - - static void repatchInt32(void* where, int32_t value) - { - setInt32(where, value); - } - - static void repatchPointer(void* where, void* value) - { - setPointer(where, value); - } - - static void repatchLoadPtrToLEA(void* where) - { -#if CPU(X86_64) - // On x86-64 pointer memory accesses require a 64-bit operand, and as such a REX prefix. - // Skip over the prefix byte. - where = reinterpret_cast<char*>(where) + 1; -#endif - *reinterpret_cast<unsigned char*>(where) = static_cast<unsigned char>(OP_LEA); - } - - static unsigned getCallReturnOffset(JmpSrc call) - { - ASSERT(call.m_offset >= 0); - return call.m_offset; - } - - static void* getRelocatedAddress(void* code, JmpSrc jump) - { - ASSERT(jump.m_offset != -1); - - return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + jump.m_offset); - } - - static void* getRelocatedAddress(void* code, JmpDst destination) - { - ASSERT(destination.m_offset != -1); - - return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + destination.m_offset); - } - - static int getDifferenceBetweenLabels(JmpDst src, JmpDst dst) - { - return dst.m_offset - src.m_offset; - } - - static int getDifferenceBetweenLabels(JmpDst src, JmpSrc dst) - { - return dst.m_offset - src.m_offset; - } - - static int getDifferenceBetweenLabels(JmpSrc src, JmpDst dst) - { - return dst.m_offset - src.m_offset; - } - - void* executableCopy(ExecutablePool* allocator) - { - void* copy = m_formatter.executableCopy(allocator); - ASSERT(copy); - return copy; - } - -private: - - static void setPointer(void* where, void* value) - { - reinterpret_cast<void**>(where)[-1] = value; - } - - static void setInt32(void* where, int32_t value) - { - reinterpret_cast<int32_t*>(where)[-1] = value; - } - - static void setRel32(void* from, void* to) - { - intptr_t offset = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from); - ASSERT(offset == static_cast<int32_t>(offset)); - - setInt32(from, offset); - } - - class X86InstructionFormatter { - - static const int maxInstructionSize = 16; - - public: - - // Legacy prefix bytes: - // - // These are emmitted prior to the instruction. - - void prefix(OneByteOpcodeID pre) - { - m_buffer.putByte(pre); - } - - // Word-sized operands / no operand instruction formatters. - // - // In addition to the opcode, the following operand permutations are supported: - // * None - instruction takes no operands. - // * One register - the low three bits of the RegisterID are added into the opcode. - // * Two registers - encode a register form ModRm (for all ModRm formats, the reg field is passed first, and a GroupOpcodeID may be passed in its place). - // * Three argument ModRM - a register, and a register and an offset describing a memory operand. - // * Five argument ModRM - a register, and a base register, an index, scale, and offset describing a memory operand. - // - // For 32-bit x86 targets, the address operand may also be provided as a void*. - // On 64-bit targets REX prefixes will be planted as necessary, where high numbered registers are used. - // - // The twoByteOp methods plant two-byte Intel instructions sequences (first opcode byte 0x0F). - - void oneByteOp(OneByteOpcodeID opcode) - { - m_buffer.ensureSpace(maxInstructionSize); - m_buffer.putByteUnchecked(opcode); - } - - void oneByteOp(OneByteOpcodeID opcode, RegisterID reg) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIfNeeded(0, 0, reg); - m_buffer.putByteUnchecked(opcode + (reg & 7)); - } - - void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID rm) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIfNeeded(reg, 0, rm); - m_buffer.putByteUnchecked(opcode); - registerModRM(reg, rm); - } - - void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIfNeeded(reg, 0, base); - m_buffer.putByteUnchecked(opcode); - memoryModRM(reg, base, offset); - } - - void oneByteOp_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIfNeeded(reg, 0, base); - m_buffer.putByteUnchecked(opcode); - memoryModRM_disp32(reg, base, offset); - } - - void oneByteOp(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIfNeeded(reg, index, base); - m_buffer.putByteUnchecked(opcode); - memoryModRM(reg, base, index, scale, offset); - } - -#if !CPU(X86_64) - void oneByteOp(OneByteOpcodeID opcode, int reg, void* address) - { - m_buffer.ensureSpace(maxInstructionSize); - m_buffer.putByteUnchecked(opcode); - memoryModRM(reg, address); - } -#endif - - void twoByteOp(TwoByteOpcodeID opcode) - { - m_buffer.ensureSpace(maxInstructionSize); - m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); - m_buffer.putByteUnchecked(opcode); - } - - void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID rm) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIfNeeded(reg, 0, rm); - m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); - m_buffer.putByteUnchecked(opcode); - registerModRM(reg, rm); - } - - void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID base, int offset) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIfNeeded(reg, 0, base); - m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); - m_buffer.putByteUnchecked(opcode); - memoryModRM(reg, base, offset); - } - - void twoByteOp(TwoByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIfNeeded(reg, index, base); - m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); - m_buffer.putByteUnchecked(opcode); - memoryModRM(reg, base, index, scale, offset); - } - -#if !CPU(X86_64) - void twoByteOp(TwoByteOpcodeID opcode, int reg, const void* address) - { - m_buffer.ensureSpace(maxInstructionSize); - m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); - m_buffer.putByteUnchecked(opcode); - memoryModRM(reg, address); - } -#endif - -#if CPU(X86_64) - // Quad-word-sized operands: - // - // Used to format 64-bit operantions, planting a REX.w prefix. - // When planting d64 or f64 instructions, not requiring a REX.w prefix, - // the normal (non-'64'-postfixed) formatters should be used. - - void oneByteOp64(OneByteOpcodeID opcode) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexW(0, 0, 0); - m_buffer.putByteUnchecked(opcode); - } - - void oneByteOp64(OneByteOpcodeID opcode, RegisterID reg) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexW(0, 0, reg); - m_buffer.putByteUnchecked(opcode + (reg & 7)); - } - - void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID rm) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexW(reg, 0, rm); - m_buffer.putByteUnchecked(opcode); - registerModRM(reg, rm); - } - - void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexW(reg, 0, base); - m_buffer.putByteUnchecked(opcode); - memoryModRM(reg, base, offset); - } - - void oneByteOp64_disp32(OneByteOpcodeID opcode, int reg, RegisterID base, int offset) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexW(reg, 0, base); - m_buffer.putByteUnchecked(opcode); - memoryModRM_disp32(reg, base, offset); - } - - void oneByteOp64(OneByteOpcodeID opcode, int reg, RegisterID base, RegisterID index, int scale, int offset) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexW(reg, index, base); - m_buffer.putByteUnchecked(opcode); - memoryModRM(reg, base, index, scale, offset); - } - - void twoByteOp64(TwoByteOpcodeID opcode, int reg, RegisterID rm) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexW(reg, 0, rm); - m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); - m_buffer.putByteUnchecked(opcode); - registerModRM(reg, rm); - } -#endif - - // Byte-operands: - // - // These methods format byte operations. Byte operations differ from the normal - // formatters in the circumstances under which they will decide to emit REX prefixes. - // These should be used where any register operand signifies a byte register. - // - // The disctinction is due to the handling of register numbers in the range 4..7 on - // x86-64. These register numbers may either represent the second byte of the first - // four registers (ah..bh) or the first byte of the second four registers (spl..dil). - // - // Since ah..bh cannot be used in all permutations of operands (specifically cannot - // be accessed where a REX prefix is present), these are likely best treated as - // deprecated. In order to ensure the correct registers spl..dil are selected a - // REX prefix will be emitted for any byte register operand in the range 4..15. - // - // These formatters may be used in instructions where a mix of operand sizes, in which - // case an unnecessary REX will be emitted, for example: - // movzbl %al, %edi - // In this case a REX will be planted since edi is 7 (and were this a byte operand - // a REX would be required to specify dil instead of bh). Unneeded REX prefixes will - // be silently ignored by the processor. - // - // Address operands should still be checked using regRequiresRex(), while byteRegRequiresRex() - // is provided to check byte register operands. - - void oneByteOp8(OneByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIf(byteRegRequiresRex(rm), 0, 0, rm); - m_buffer.putByteUnchecked(opcode); - registerModRM(groupOp, rm); - } - - void twoByteOp8(TwoByteOpcodeID opcode, RegisterID reg, RegisterID rm) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIf(byteRegRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm); - m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); - m_buffer.putByteUnchecked(opcode); - registerModRM(reg, rm); - } - - void twoByteOp8(TwoByteOpcodeID opcode, GroupOpcodeID groupOp, RegisterID rm) - { - m_buffer.ensureSpace(maxInstructionSize); - emitRexIf(byteRegRequiresRex(rm), 0, 0, rm); - m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE); - m_buffer.putByteUnchecked(opcode); - registerModRM(groupOp, rm); - } - - // Immediates: - // - // An immedaite should be appended where appropriate after an op has been emitted. - // The writes are unchecked since the opcode formatters above will have ensured space. - - void immediate8(int imm) - { - m_buffer.putByteUnchecked(imm); - } - - void immediate16(int imm) - { - m_buffer.putShortUnchecked(imm); - } - - void immediate32(int imm) - { - m_buffer.putIntUnchecked(imm); - } - - void immediate64(int64_t imm) - { - m_buffer.putInt64Unchecked(imm); - } - - JmpSrc immediateRel32() - { - m_buffer.putIntUnchecked(0); - return JmpSrc(m_buffer.size()); - } - - // Administrative methods: - - size_t size() const { return m_buffer.size(); } - bool isAligned(int alignment) const { return m_buffer.isAligned(alignment); } - void* data() const { return m_buffer.data(); } - void* executableCopy(ExecutablePool* allocator) { return m_buffer.executableCopy(allocator); } - - private: - - // Internals; ModRm and REX formatters. - - static const RegisterID noBase = X86Registers::ebp; - static const RegisterID hasSib = X86Registers::esp; - static const RegisterID noIndex = X86Registers::esp; -#if CPU(X86_64) - static const RegisterID noBase2 = X86Registers::r13; - static const RegisterID hasSib2 = X86Registers::r12; - - // Registers r8 & above require a REX prefixe. - inline bool regRequiresRex(int reg) - { - return (reg >= X86Registers::r8); - } - - // Byte operand register spl & above require a REX prefix (to prevent the 'H' registers be accessed). - inline bool byteRegRequiresRex(int reg) - { - return (reg >= X86Registers::esp); - } - - // Format a REX prefix byte. - inline void emitRex(bool w, int r, int x, int b) - { - m_buffer.putByteUnchecked(PRE_REX | ((int)w << 3) | ((r>>3)<<2) | ((x>>3)<<1) | (b>>3)); - } - - // Used to plant a REX byte with REX.w set (for 64-bit operations). - inline void emitRexW(int r, int x, int b) - { - emitRex(true, r, x, b); - } - - // Used for operations with byte operands - use byteRegRequiresRex() to check register operands, - // regRequiresRex() to check other registers (i.e. address base & index). - inline void emitRexIf(bool condition, int r, int x, int b) - { - if (condition) emitRex(false, r, x, b); - } - - // Used for word sized operations, will plant a REX prefix if necessary (if any register is r8 or above). - inline void emitRexIfNeeded(int r, int x, int b) - { - emitRexIf(regRequiresRex(r) || regRequiresRex(x) || regRequiresRex(b), r, x, b); - } -#else - // No REX prefix bytes on 32-bit x86. - inline bool regRequiresRex(int) { return false; } - inline bool byteRegRequiresRex(int) { return false; } - inline void emitRexIf(bool, int, int, int) {} - inline void emitRexIfNeeded(int, int, int) {} -#endif - - enum ModRmMode { - ModRmMemoryNoDisp, - ModRmMemoryDisp8, - ModRmMemoryDisp32, - ModRmRegister, - }; - - void putModRm(ModRmMode mode, int reg, RegisterID rm) - { - m_buffer.putByteUnchecked((mode << 6) | ((reg & 7) << 3) | (rm & 7)); - } - - void putModRmSib(ModRmMode mode, int reg, RegisterID base, RegisterID index, int scale) - { - ASSERT(mode != ModRmRegister); - - putModRm(mode, reg, hasSib); - m_buffer.putByteUnchecked((scale << 6) | ((index & 7) << 3) | (base & 7)); - } - - void registerModRM(int reg, RegisterID rm) - { - putModRm(ModRmRegister, reg, rm); - } - - void memoryModRM(int reg, RegisterID base, int offset) - { - // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there. -#if CPU(X86_64) - if ((base == hasSib) || (base == hasSib2)) { -#else - if (base == hasSib) { -#endif - if (!offset) // No need to check if the base is noBase, since we know it is hasSib! - putModRmSib(ModRmMemoryNoDisp, reg, base, noIndex, 0); - else if (CAN_SIGN_EXTEND_8_32(offset)) { - putModRmSib(ModRmMemoryDisp8, reg, base, noIndex, 0); - m_buffer.putByteUnchecked(offset); - } else { - putModRmSib(ModRmMemoryDisp32, reg, base, noIndex, 0); - m_buffer.putIntUnchecked(offset); - } - } else { -#if CPU(X86_64) - if (!offset && (base != noBase) && (base != noBase2)) -#else - if (!offset && (base != noBase)) -#endif - putModRm(ModRmMemoryNoDisp, reg, base); - else if (CAN_SIGN_EXTEND_8_32(offset)) { - putModRm(ModRmMemoryDisp8, reg, base); - m_buffer.putByteUnchecked(offset); - } else { - putModRm(ModRmMemoryDisp32, reg, base); - m_buffer.putIntUnchecked(offset); - } - } - } - - void memoryModRM_disp32(int reg, RegisterID base, int offset) - { - // A base of esp or r12 would be interpreted as a sib, so force a sib with no index & put the base in there. -#if CPU(X86_64) - if ((base == hasSib) || (base == hasSib2)) { -#else - if (base == hasSib) { -#endif - putModRmSib(ModRmMemoryDisp32, reg, base, noIndex, 0); - m_buffer.putIntUnchecked(offset); - } else { - putModRm(ModRmMemoryDisp32, reg, base); - m_buffer.putIntUnchecked(offset); - } - } - - void memoryModRM(int reg, RegisterID base, RegisterID index, int scale, int offset) - { - ASSERT(index != noIndex); - -#if CPU(X86_64) - if (!offset && (base != noBase) && (base != noBase2)) -#else - if (!offset && (base != noBase)) -#endif - putModRmSib(ModRmMemoryNoDisp, reg, base, index, scale); - else if (CAN_SIGN_EXTEND_8_32(offset)) { - putModRmSib(ModRmMemoryDisp8, reg, base, index, scale); - m_buffer.putByteUnchecked(offset); - } else { - putModRmSib(ModRmMemoryDisp32, reg, base, index, scale); - m_buffer.putIntUnchecked(offset); - } - } - -#if !CPU(X86_64) - void memoryModRM(int reg, const void* address) - { - // noBase + ModRmMemoryNoDisp means noBase + ModRmMemoryDisp32! - putModRm(ModRmMemoryNoDisp, reg, noBase); - m_buffer.putIntUnchecked(reinterpret_cast<int32_t>(address)); - } -#endif - - AssemblerBuffer m_buffer; - } m_formatter; -}; - -} // namespace JSC - -#endif // ENABLE(ASSEMBLER) && CPU(X86) - -#endif // X86Assembler_h |