X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/93a3786624b2768d89bfa27e46598dc64e2fb70a..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/assembler/SH4Assembler.h diff --git a/assembler/SH4Assembler.h b/assembler/SH4Assembler.h index a6d3382..d326279 100644 --- a/assembler/SH4Assembler.h +++ b/assembler/SH4Assembler.h @@ -33,6 +33,7 @@ #include "AssemblerBuffer.h" #include "AssemblerBufferWithConstantPool.h" #include "JITCompilationEffort.h" +#include #include #include #include @@ -182,6 +183,7 @@ enum { FSQRT_OPCODE = 0xf06d, FSCHG_OPCODE = 0xf3fd, CLRT_OPCODE = 8, + SYNCO_OPCODE = 0x00ab, }; namespace SH4Registers { @@ -325,6 +327,12 @@ public: static const RegisterID scratchReg2 = SH4Registers::r11; static const uint32_t maxInstructionSize = 16; + static RegisterID firstRegister() { return SH4Registers::r0; } + static RegisterID lastRegister() { return SH4Registers::r15; } + + static FPRegisterID firstFPRegister() { return SH4Registers::dr0; } + static FPRegisterID lastFPRegister() { return SH4Registers::dr14; } + enum { padForAlign8 = 0x00, padForAlign16 = 0x0009, @@ -337,10 +345,14 @@ public: }; SH4Assembler() + : m_claimscratchReg(0x0) + , m_indexOfLastWatchpoint(INT_MIN) + , m_indexOfTailOfLastWatchpoint(INT_MIN) { - m_claimscratchReg = 0x0; } + SH4Buffer& buffer() { return m_buffer; } + // SH4 condition codes typedef enum { EQ = 0x0, // Equal @@ -457,7 +469,7 @@ public: void andlImm8r(int imm8, RegisterID dst) { ASSERT((imm8 <= 255) && (imm8 >= 0)); - ASSERT(dst == SH4Registers::r0); + ASSERT_UNUSED(dst, dst == SH4Registers::r0); uint16_t opc = getOpcodeGroup5(ANDIMM_OPCODE, imm8); oneShortOp(opc); @@ -490,7 +502,7 @@ public: void orlImm8r(int imm8, RegisterID dst) { ASSERT((imm8 <= 255) && (imm8 >= 0)); - ASSERT(dst == SH4Registers::r0); + ASSERT_UNUSED(dst, dst == SH4Registers::r0); uint16_t opc = getOpcodeGroup5(ORIMM_OPCODE, imm8); oneShortOp(opc); @@ -517,7 +529,7 @@ public: void xorlImm8r(int imm8, RegisterID dst) { ASSERT((imm8 <= 255) && (imm8 >= 0)); - ASSERT(dst == SH4Registers::r0); + ASSERT_UNUSED(dst, dst == SH4Registers::r0); uint16_t opc = getOpcodeGroup5(XORIMM_OPCODE, imm8); oneShortOp(opc); @@ -685,6 +697,7 @@ public: void cmpEqImmR0(int imm, RegisterID dst) { + ASSERT_UNUSED(dst, dst == SH4Registers::r0); uint16_t opc = getOpcodeGroup5(CMPEQIMM_OPCODE, imm); oneShortOp(opc); } @@ -697,7 +710,8 @@ public: void testlImm8r(int imm, RegisterID dst) { - ASSERT((dst == SH4Registers::r0) && (imm <= 255) && (imm >= 0)); + ASSERT((imm <= 255) && (imm >= 0)); + ASSERT_UNUSED(dst, dst == SH4Registers::r0); uint16_t opc = getOpcodeGroup5(TSTIMM_OPCODE, imm); oneShortOp(opc); @@ -708,6 +722,11 @@ public: oneShortOp(NOP_OPCODE, false); } + void synco() + { + oneShortOp(SYNCO_OPCODE); + } + void sett() { oneShortOp(SETT_OPCODE); @@ -1060,7 +1079,7 @@ public: void movwPCReg(int offset, RegisterID base, RegisterID dst) { - ASSERT(base == SH4Registers::pc); + ASSERT_UNUSED(base, base == SH4Registers::pc); ASSERT((offset <= 255) && (offset >= 0)); uint16_t opc = getOpcodeGroup3(MOVW_READ_OFFPC_OPCODE, dst, offset); @@ -1069,7 +1088,7 @@ public: void movwMemReg(int offset, RegisterID base, RegisterID dst) { - ASSERT(dst == SH4Registers::r0); + ASSERT_UNUSED(dst, dst == SH4Registers::r0); uint16_t opc = getOpcodeGroup11(MOVW_READ_OFFRM_OPCODE, base, offset); oneShortOp(opc); @@ -1135,7 +1154,7 @@ public: void movbMemReg(int offset, RegisterID base, RegisterID dst) { - ASSERT(dst == SH4Registers::r0); + ASSERT_UNUSED(dst, dst == SH4Registers::r0); uint16_t opc = getOpcodeGroup11(MOVB_READ_OFFRM_OPCODE, base, offset); oneShortOp(opc); @@ -1189,14 +1208,6 @@ public: oneShortOp(opc); } - void movlImm8r(int imm8, RegisterID dst) - { - ASSERT((imm8 <= 127) && (imm8 >= -128)); - - uint16_t opc = getOpcodeGroup3(MOVIMM_OPCODE, dst, imm8); - oneShortOp(opc); - } - void loadConstant(uint32_t constant, RegisterID dst) { if (((int)constant <= 0x7f) && ((int)constant >= -0x80)) { @@ -1247,19 +1258,19 @@ public: { RegisterID scr = claimScratch(); m_buffer.ensureSpace(maxInstructionSize + 4, sizeof(uint32_t)); - AssemblerLabel label = m_buffer.label(); loadConstantUnReusable(0x0, scr); branch(BRAF_OPCODE, scr); nop(); releaseScratch(scr); - return label; + return m_buffer.label(); } - void extraInstrForBranch(RegisterID dst) + AssemblerLabel extraInstrForBranch(RegisterID dst) { loadConstantUnReusable(0x0, dst); + branch(BRAF_OPCODE, dst); nop(); - nop(); + return m_buffer.label(); } AssemblerLabel jmp(RegisterID dst) @@ -1277,23 +1288,20 @@ public: AssemblerLabel jne() { - AssemblerLabel label = m_buffer.label(); branch(BF_OPCODE, 0); - return label; + return m_buffer.label(); } AssemblerLabel je() { - AssemblerLabel label = m_buffer.label(); branch(BT_OPCODE, 0); - return label; + return m_buffer.label(); } AssemblerLabel bra() { - AssemblerLabel label = m_buffer.label(); branch(BRA_OPCODE, 0); - return label; + return m_buffer.label(); } void ret() @@ -1308,10 +1316,25 @@ public: return m_buffer.label(); } - AssemblerLabel label() + AssemblerLabel labelForWatchpoint() { m_buffer.ensureSpaceForAnyInstruction(); - return m_buffer.label(); + AssemblerLabel result = m_buffer.label(); + if (static_cast(result.m_offset) != m_indexOfLastWatchpoint) + result = label(); + m_indexOfLastWatchpoint = result.m_offset; + m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize(); + return result; + } + + AssemblerLabel label() + { + AssemblerLabel result = labelIgnoringWatchpoints(); + while (UNLIKELY(static_cast(result.m_offset) < m_indexOfTailOfLastWatchpoint)) { + nop(); + result = labelIgnoringWatchpoints(); + } + return result; } int sizeOfConstantPool() @@ -1331,12 +1354,14 @@ public: static void changePCrelativeAddress(int offset, uint16_t* instructionPtr, uint32_t newAddress) { + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); uint32_t address = (offset << 2) + ((reinterpret_cast(instructionPtr) + 4) &(~0x3)); *reinterpret_cast(address) = newAddress; } static uint32_t readPCrelativeAddress(int offset, uint16_t* instructionPtr) { + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); uint32_t address = (offset << 2) + ((reinterpret_cast(instructionPtr) + 4) &(~0x3)); return *reinterpret_cast(address); } @@ -1350,41 +1375,16 @@ public: { ASSERT(from.isSet()); - uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset); - uint16_t instruction = *instructionPtr; + uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset) - 3; int offsetBits = (reinterpret_cast(to) - reinterpret_cast(code)) - from.m_offset; - if (((instruction & 0xff00) == BT_OPCODE) || ((instruction & 0xff00) == BF_OPCODE)) { - /* BT label ==> BF 2 - nop LDR reg - nop braf @reg - nop nop - */ - offsetBits -= 8; - instruction ^= 0x0202; - *instructionPtr++ = instruction; - changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits); - instruction = (BRAF_OPCODE | (*instructionPtr++ & 0xf00)); - *instructionPtr = instruction; - printBlockInstr(instructionPtr - 2, from.m_offset, 3); - return; - } - - /* MOV #imm, reg => LDR reg - braf @reg braf @reg - nop nop - */ - ASSERT((*(instructionPtr + 1) & BRAF_OPCODE) == BRAF_OPCODE); - - offsetBits -= 4; - if (offsetBits >= -4096 && offsetBits <= 4094) { - *instructionPtr = getOpcodeGroup6(BRA_OPCODE, offsetBits >> 1); - *(++instructionPtr) = NOP_OPCODE; - printBlockInstr(instructionPtr - 1, from.m_offset, 2); - return; - } - - changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits - 2); + /* MOV #imm, reg => LDR reg + braf @reg braf @reg + nop nop + */ + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); + ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE); + changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits); printInstr(*instructionPtr, from.m_offset + 2); } @@ -1392,12 +1392,14 @@ public: { uint16_t* instructionPtr = getInstructionPtr(code, from.m_offset); instructionPtr -= 3; + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast(to)); } static void linkPointer(void* code, AssemblerLabel where, void* value) { uint16_t* instructionPtr = getInstructionPtr(code, where.m_offset); + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast(value)); } @@ -1441,7 +1443,7 @@ public: ASSERT((((reinterpret_cast(constPoolAddr) - reinterpret_cast(loadAddr)) + index * 4)) < 1024); int offset = reinterpret_cast(constPoolAddr) + (index * 4) - ((reinterpret_cast(instructionPtr) & ~0x03) + 4); - instruction &=0xf00; + instruction &= 0x0f00; instruction |= 0xd000; offset &= 0x03ff; instruction |= (offset >> 2); @@ -1462,51 +1464,40 @@ public: static void repatchInt32(void* where, int32_t value) { uint16_t* instructionPtr = reinterpret_cast(where); + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, value); } static void repatchCompact(void* where, int32_t value) { + uint16_t* instructionPtr = reinterpret_cast(where); ASSERT(value >= 0); ASSERT(value <= 60); - *reinterpret_cast(where) = ((*reinterpret_cast(where) & 0xfff0) | (value >> 2)); - cacheFlush(reinterpret_cast(where), sizeof(uint16_t)); + + // Handle the uncommon case where a flushConstantPool occured in movlMemRegCompact. + if ((instructionPtr[0] & 0xf000) == BRA_OPCODE) + instructionPtr += (instructionPtr[0] & 0x0fff) + 2; + + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFRM_OPCODE); + instructionPtr[0] = (instructionPtr[0] & 0xfff0) | (value >> 2); + cacheFlush(instructionPtr, sizeof(uint16_t)); } static void relinkCall(void* from, void* to) { uint16_t* instructionPtr = reinterpret_cast(from); instructionPtr -= 3; + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast(to)); } static void relinkJump(void* from, void* to) { uint16_t* instructionPtr = reinterpret_cast (from); - uint16_t instruction = *instructionPtr; - int32_t offsetBits = (reinterpret_cast(to) - reinterpret_cast(from)); - - if (((*instructionPtr & 0xff00) == BT_OPCODE) || ((*instructionPtr & 0xff00) == BF_OPCODE)) { - offsetBits -= 8; - instructionPtr++; - changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits); - instruction = (BRAF_OPCODE | (*instructionPtr++ & 0xf00)); - *instructionPtr = instruction; - printBlockInstr(instructionPtr, reinterpret_cast(from) + 1, 3); - return; - } - - ASSERT((*(instructionPtr + 1) & BRAF_OPCODE) == BRAF_OPCODE); - offsetBits -= 4; - if (offsetBits >= -4096 && offsetBits <= 4094) { - *instructionPtr = getOpcodeGroup6(BRA_OPCODE, offsetBits >> 1); - *(++instructionPtr) = NOP_OPCODE; - printBlockInstr(instructionPtr - 2, reinterpret_cast(from), 2); - return; - } - - changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits - 2); - printInstr(*instructionPtr, reinterpret_cast(from)); + instructionPtr -= 3; + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); + ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE); + changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, reinterpret_cast(to) - reinterpret_cast(from)); } // Linking & patching @@ -1519,33 +1510,52 @@ public: static void replaceWithJump(void *instructionStart, void *to) { SH4Word* instruction = reinterpret_cast(instructionStart); - intptr_t difference = reinterpret_cast(to) - (reinterpret_cast(instruction) + 2 * sizeof(SH4Word)); - int nbinst = 0; - - if ((difference >= -4096) && (difference <= 4094)) { - instruction[0] = getOpcodeGroup6(BRA_OPCODE, difference >> 1); - instruction[1] = NOP_OPCODE; - cacheFlush(instruction, sizeof(SH4Word) * 2); - return; + intptr_t difference = reinterpret_cast(to) - (reinterpret_cast(instruction) + 3 * sizeof(SH4Word)); + + if ((instruction[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE) { + // We have an entry in constant pool and we potentially replace a branchPtrWithPatch, so let's backup what would be the + // condition (CMP/xx and Bx opcodes) for later use in revertJumpReplacementToBranchPtrWithPatch before putting the jump. + instruction[4] = instruction[1]; + instruction[5] = instruction[2]; + instruction[1] = (BRAF_OPCODE | (instruction[0] & 0x0f00)); + instruction[2] = NOP_OPCODE; + cacheFlush(&instruction[1], 2 * sizeof(SH4Word)); + } else { + instruction[0] = getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, SH4Registers::r13, 1); + instruction[1] = getOpcodeGroup2(BRAF_OPCODE, SH4Registers::r13); + instruction[2] = NOP_OPCODE; + cacheFlush(instruction, 3 * sizeof(SH4Word)); } - instruction[nbinst++] = getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, scratchReg2, 1); - instruction[nbinst++] = getOpcodeGroup2(JMP_OPCODE, scratchReg2); - instruction[nbinst++] = NOP_OPCODE; - - if (!(reinterpret_cast(instruction) & 3)) - instruction[nbinst++] = NOP_OPCODE; - - instruction[nbinst++] = reinterpret_cast(to) & 0xffff; - instruction[nbinst++] = reinterpret_cast(to) >> 16; - cacheFlush(instruction, sizeof(SH4Word) * nbinst); + changePCrelativeAddress(instruction[0] & 0x00ff, instruction, difference); } - static void revertJump(void* instructionStart, void *immptr) + static void revertJumpReplacementToBranchPtrWithPatch(void* instructionStart, RegisterID rd, int imm) { SH4Word *insn = reinterpret_cast(instructionStart); ASSERT((insn[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); - changePCrelativeAddress(insn[0] & 0x00ff, insn, reinterpret_cast(immptr)); + ASSERT((insn[0] & 0x00ff) != 1); + + insn[0] = getOpcodeGroup3(MOVL_READ_OFFPC_OPCODE, SH4Registers::r13, insn[0] & 0x00ff); + if ((insn[1] & 0xf0ff) == BRAF_OPCODE) { + insn[1] = (insn[4] & 0xf00f) | (rd << 8) | (SH4Registers::r13 << 4); // Restore CMP/xx opcode. + insn[2] = insn[5]; + ASSERT(((insn[2] & 0xff00) == BT_OPCODE) || ((insn[2] & 0xff00) == BF_OPCODE)); + ASSERT((insn[3] & 0xf000) == MOVL_READ_OFFPC_OPCODE); + insn[4] = (BRAF_OPCODE | (insn[3] & 0x0f00)); + insn[5] = NOP_OPCODE; + cacheFlush(insn, 6 * sizeof(SH4Word)); + } else { + // The branchPtrWithPatch has already been restored, so we just patch the immediate value and ASSERT all is as expected. + ASSERT((insn[1] & 0xf000) == 0x3000); + insn[1] = (insn[1] & 0xf00f) | (rd << 8) | (SH4Registers::r13 << 4); + cacheFlush(insn, 2 * sizeof(SH4Word)); + ASSERT(((insn[2] & 0xff00) == BT_OPCODE) || ((insn[2] & 0xff00) == BF_OPCODE)); + ASSERT((insn[3] & 0xf000) == MOVL_READ_OFFPC_OPCODE); + ASSERT(insn[5] == NOP_OPCODE); + } + + changePCrelativeAddress(insn[0] & 0x00ff, insn, imm); } void linkJump(AssemblerLabel from, AssemblerLabel to, JumpType type = JumpFar) @@ -1553,60 +1563,35 @@ public: ASSERT(to.isSet()); ASSERT(from.isSet()); - uint16_t* instructionPtr = getInstructionPtr(data(), from.m_offset); - uint16_t instruction = *instructionPtr; - int offsetBits; + uint16_t* instructionPtr = getInstructionPtr(data(), from.m_offset) - 1; + int offsetBits = (to.m_offset - from.m_offset); if (type == JumpNear) { - ASSERT((instruction == BT_OPCODE) || (instruction == BF_OPCODE) || (instruction == BRA_OPCODE)); - int offset = (codeSize() - from.m_offset) - 4; + uint16_t instruction = instructionPtr[0]; + int offset = (offsetBits - 2); + ASSERT((((instruction == BT_OPCODE) || (instruction == BF_OPCODE)) && (offset >= -256) && (offset <= 254)) + || ((instruction == BRA_OPCODE) && (offset >= -4096) && (offset <= 4094))); *instructionPtr++ = instruction | (offset >> 1); printInstr(*instructionPtr, from.m_offset + 2); return; } - if (((instruction & 0xff00) == BT_OPCODE) || ((instruction & 0xff00) == BF_OPCODE)) { - /* BT label => BF 2 - nop LDR reg - nop braf @reg - nop nop - */ - offsetBits = (to.m_offset - from.m_offset) - 8; - instruction ^= 0x0202; - *instructionPtr++ = instruction; - if ((*instructionPtr & 0xf000) == 0xe000) { - uint32_t* addr = getLdrImmAddressOnPool(instructionPtr, m_buffer.poolAddress()); - *addr = offsetBits; - } else - changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits); - instruction = (BRAF_OPCODE | (*instructionPtr++ & 0xf00)); - *instructionPtr = instruction; - printBlockInstr(instructionPtr - 2, from.m_offset, 3); - return; - } - /* MOV # imm, reg => LDR reg braf @reg braf @reg nop nop */ - ASSERT((*(instructionPtr + 1) & BRAF_OPCODE) == BRAF_OPCODE); - offsetBits = (to.m_offset - from.m_offset) - 4; - if (offsetBits >= -4096 && offsetBits <= 4094) { - *instructionPtr = getOpcodeGroup6(BRA_OPCODE, offsetBits >> 1); - *(++instructionPtr) = NOP_OPCODE; - printBlockInstr(instructionPtr - 1, from.m_offset, 2); - return; - } + instructionPtr -= 2; + ASSERT((instructionPtr[1] & 0xf0ff) == BRAF_OPCODE); - instruction = *instructionPtr; - if ((instruction & 0xf000) == 0xe000) { + if ((instructionPtr[0] & 0xf000) == MOVIMM_OPCODE) { uint32_t* addr = getLdrImmAddressOnPool(instructionPtr, m_buffer.poolAddress()); - *addr = offsetBits - 2; + *addr = offsetBits; printInstr(*instructionPtr, from.m_offset + 2); return; } - changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits - 2); + ASSERT((instructionPtr[0] & 0xf000) == MOVL_READ_OFFPC_OPCODE); + changePCrelativeAddress((*instructionPtr & 0xff), instructionPtr, offsetBits); printInstr(*instructionPtr, from.m_offset + 2); } @@ -1647,11 +1632,6 @@ public: return reinterpret_cast(readPCrelativeAddress((*instructionPtr & 0xff), instructionPtr)); } - PassRefPtr executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort) - { - return m_buffer.executableCopy(vm, ownerUID, effort); - } - static void cacheFlush(void* code, size_t size) { #if OS(LINUX) @@ -1699,6 +1679,8 @@ public: void* data() const { return m_buffer.data(); } size_t codeSize() const { return m_buffer.codeSize(); } + unsigned debugOffset() { return m_buffer.debugOffset(); } + #ifdef SH4_ASSEMBLER_TRACING static void printInstr(uint16_t opc, unsigned size, bool isdoubleInst = true) { @@ -2201,8 +2183,8 @@ public: printfStdoutInstr(">> end repatch\n"); } #else - static void printInstr(uint16_t opc, unsigned size, bool isdoubleInst = true) { }; - static void printBlockInstr(uint16_t* first, unsigned offset, int nbInstr) { }; + static void printInstr(uint16_t, unsigned, bool = true) { }; + static void printBlockInstr(uint16_t*, unsigned, int) { }; #endif static void replaceWithLoad(void* instructionStart) @@ -2232,6 +2214,8 @@ public: private: SH4Buffer m_buffer; int m_claimscratchReg; + int m_indexOfLastWatchpoint; + int m_indexOfTailOfLastWatchpoint; }; } // namespace JSC