diff options
Diffstat (limited to 'vm/compiler/codegen/armv5te/Assemble.c')
-rw-r--r-- | vm/compiler/codegen/armv5te/Assemble.c | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/vm/compiler/codegen/armv5te/Assemble.c b/vm/compiler/codegen/armv5te/Assemble.c new file mode 100644 index 000000000..14355cb28 --- /dev/null +++ b/vm/compiler/codegen/armv5te/Assemble.c @@ -0,0 +1,499 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Dalvik.h" +#include "libdex/OpCode.h" +#include "dexdump/OpCodeNames.h" + +#include "../../CompilerInternals.h" +#include "Armv5teLIR.h" +#include <unistd.h> /* for cacheflush */ + +/* + * opcode: Armv5teOpCode enum + * skeleton: pre-designated bit-pattern for this opcode + * ds: dest start bit position + * de: dest end bit position + * s1s: src1 start bit position + * s1e: src1 end bit position + * s2s: src2 start bit position + * s2e: src2 end bit position + * operands: number of operands (for sanity check purposes) + * name: mnemonic name + * fmt: for pretty-prining + */ +#define ENCODING_MAP(opcode, skeleton, ds, de, s1s, s1e, s2s, s2e, operands, \ + name, fmt) \ + {skeleton, {{ds, de}, {s1s, s1e}, {s2s, s2e}}, opcode, operands, name, \ + fmt} + +/* Instruction dump string format keys: !pf, where "!" is the start + * of the key, "p" is which numeric operand to use and "f" is the + * print format. + * + * [p]ositions: + * 0 -> operands[0] (dest) + * 1 -> operands[1] (src1) + * 2 -> operands[2] (src2) + * + * [f]ormats: + * h -> 4-digit hex + * d -> decimal + * D -> decimal+8 (used to convert 3-bit regnum field to high reg) + * E -> decimal*4 + * F -> decimal*2 + * c -> branch condition (beq, bne, etc.) + * t -> pc-relative target + * u -> 1st half of bl[x] target + * v -> 2nd half ob bl[x] target + * R -> register list + * + * [!] escape. To insert "!", use "!!" + */ +/* NOTE: must be kept in sync with enum Armv5teOpcode from Armv5teLIR.h */ +Armv5teEncodingMap EncodingMap[ARMV5TE_LAST] = { + ENCODING_MAP(ARMV5TE_16BIT_DATA, 0x0000, 15, 0, -1, -1, -1, -1, + 1, "data", "0x!0h(!0d)"), + ENCODING_MAP(ARMV5TE_ADC, 0x4140, 2, 0, 5, 3, -1, -1, + 2, "adc", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_ADD_RRI3, 0x1c00, 2, 0, 5, 3, 8, 6, + 3, "add", "r!0d, r!1d, #!2d"), + ENCODING_MAP(ARMV5TE_ADD_RI8, 0x3000, 10, 8, 7, 0, -1, -1, + 2, "add", "r!0d, r!0d, #!1d"), + ENCODING_MAP(ARMV5TE_ADD_RRR, 0x1800, 2, 0, 5, 3, 8, 6, + 3, "add", "r!0d, r!1d, r!2d"), + ENCODING_MAP(ARMV5TE_ADD_RR_LH, 0x4440, 2, 0, 5, 3, -1, -1, + 2, "add", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_ADD_RR_HL, 0x4480, 2, 0, 5, 3, -1, -1, + 2, "add", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_ADD_RR_HH, 0x44c0, 2, 0, 5, 3, -1, -1, + 2, "add", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_ADD_PC_REL, 0xa000, 10, 8, 7, 0, -1, -1, + 2, "add", "r!0d, pc, #!1E"), + ENCODING_MAP(ARMV5TE_ADD_SP_REL, 0xa800, 10, 8, 7, 0, -1, -1, + 2, "add", "r!0d, sp, #!1E"), + ENCODING_MAP(ARMV5TE_ADD_SPI7, 0xb000, 6, 0, -1, -1, -1, -1, + 1, "add", "sp, #!0d*4"), + ENCODING_MAP(ARMV5TE_AND_RR, 0x4000, 2, 0, 5, 3, -1, -1, + 2, "and", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_ASR, 0x1000, 2, 0, 5, 3, 10, 6, + 3, "asr", "r!0d, r!1d, #!2d"), + ENCODING_MAP(ARMV5TE_ASRV, 0x4100, 2, 0, 5, 3, -1, -1, + 2, "asr", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_B_COND, 0xd000, 7, 0, 11, 8, -1, -1, + 2, "!1c", "!0t"), + ENCODING_MAP(ARMV5TE_B_UNCOND, 0xe000, 10, 0, -1, -1, -1, -1, + 0, "b", "!0t"), + ENCODING_MAP(ARMV5TE_BIC, 0x4380, 2, 0, 5, 3, -1, -1, + 2, "bic", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_BKPT, 0xbe00, 7, 0, -1, -1, -1, -1, + 1, "bkpt", "!0d"), + ENCODING_MAP(ARMV5TE_BLX_1, 0xf000, 10, 0, -1, -1, -1, -1, + 2, "blx_1", "!0u"), + ENCODING_MAP(ARMV5TE_BLX_2, 0xe800, 10, 0, -1, -1, -1, -1, + 2, "blx_2", "!0v"), + ENCODING_MAP(ARMV5TE_BL_1, 0xf000, 10, 0, -1, -1, -1, -1, + 1, "bl_1", "!0u"), + ENCODING_MAP(ARMV5TE_BL_2, 0xf800, 10, 0, -1, -1, -1, -1, + 1, "bl_2", "!0v"), + ENCODING_MAP(ARMV5TE_BLX_R, 0x4780, 6, 3, -1, -1, -1, -1, + 1, "blx", "r!0d"), + ENCODING_MAP(ARMV5TE_BX, 0x4700, 6, 3, -1, -1, -1, -1, + 1, "bx", "r!0d"), + ENCODING_MAP(ARMV5TE_CMN, 0x42c0, 2, 0, 5, 3, -1, -1, + 2, "cmn", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_CMP_RI8, 0x2800, 10, 8, 7, 0, -1, -1, + 2, "cmp", "r!0d, #!1d"), + ENCODING_MAP(ARMV5TE_CMP_RR, 0x4280, 2, 0, 5, 3, -1, -1, + 2, "cmp", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_CMP_LH, 0x4540, 2, 0, 5, 3, -1, -1, + 2, "cmp", "r!0d, r!1D"), + ENCODING_MAP(ARMV5TE_CMP_HL, 0x4580, 2, 0, 5, 3, -1, -1, + 2, "cmp", "r!0D, r!1d"), + ENCODING_MAP(ARMV5TE_CMP_HH, 0x45c0, 2, 0, 5, 3, -1, -1, + 2, "cmp", "r!0D, r!1D"), + ENCODING_MAP(ARMV5TE_EOR, 0x4040, 2, 0, 5, 3, -1, -1, + 2, "eor", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_LDMIA, 0xc800, 10, 8, 7, 0, -1, -1, + 2, "ldmia", "r!0d!!, <!1R>"), + ENCODING_MAP(ARMV5TE_LDR_RRI5, 0x6800, 2, 0, 5, 3, 10, 6, + 3, "ldr", "r!0d, [r!1d, #!2E]"), + ENCODING_MAP(ARMV5TE_LDR_RRR, 0x5800, 2, 0, 5, 3, 8, 6, + 3, "ldr", "r!0d, [r!1d, r!2d]"), + ENCODING_MAP(ARMV5TE_LDR_PC_REL, 0x4800, 10, 8, 7, 0, -1, -1, + 2, "ldr", "r!0d, [pc, #!1E]"), + ENCODING_MAP(ARMV5TE_LDR_SP_REL, 0x9800, 10, 8, 7, 0, -1, -1, + 2, "ldr", "r!0d, [sp, #!1E]"), + ENCODING_MAP(ARMV5TE_LDRB_RRI5, 0x7800, 2, 0, 5, 3, 10, 6, + 3, "ldrb", "r!0d, [r!1d, #2d]"), + ENCODING_MAP(ARMV5TE_LDRB_RRR, 0x5c00, 2, 0, 5, 3, 8, 6, + 3, "ldrb", "r!0d, [r!1d, r!2d]"), + ENCODING_MAP(ARMV5TE_LDRH_RRI5, 0x8800, 2, 0, 5, 3, 10, 6, + 3, "ldrh", "r!0d, [r!1d, #!2F]"), + ENCODING_MAP(ARMV5TE_LDRH_RRR, 0x5a00, 2, 0, 5, 3, 8, 6, + 3, "ldrh", "r!0d, [r!1d, r!2d]"), + ENCODING_MAP(ARMV5TE_LDRSB_RRR, 0x5600, 2, 0, 5, 3, 8, 6, + 3, "ldrsb", "r!0d, [r!1d, r!2d]"), + ENCODING_MAP(ARMV5TE_LDRSH_RRR, 0x5e00, 2, 0, 5, 3, 8, 6, + 3, "ldrsh", "r!0d, [r!1d, r!2d]"), + ENCODING_MAP(ARMV5TE_LSL, 0x0000, 2, 0, 5, 3, 10, 6, + 3, "lsl", "r!0d, r!1d, #!2d"), + ENCODING_MAP(ARMV5TE_LSLV, 0x4080, 2, 0, 5, 3, -1, -1, + 2, "lsl", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_LSR, 0x0800, 2, 0, 5, 3, 10, 6, + 3, "lsr", "r!0d, r!1d, #!2d"), + ENCODING_MAP(ARMV5TE_LSRV, 0x40c0, 2, 0, 5, 3, -1, -1, + 2, "lsr", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_MOV_IMM, 0x2000, 10, 8, 7, 0, -1, -1, + 2, "mov", "r!0d, #!1d"), + ENCODING_MAP(ARMV5TE_MOV_RR, 0x1c00, 2, 0, 5, 3, -1, -1, + 2, "mov", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_MOV_RR_LH, 0x4640, 2, 0, 5, 3, -1, -1, + 2, "mov", "r!0D, r!1d"), + ENCODING_MAP(ARMV5TE_MOV_RR_HL, 0x4680, 2, 0, 5, 3, -1, -1, + 2, "mov", "r!0d, r!1D"), + ENCODING_MAP(ARMV5TE_MOV_RR_HH, 0x46c0, 2, 0, 5, 3, -1, -1, + 2, "mov", "r!0D, r!1D"), + ENCODING_MAP(ARMV5TE_MUL, 0x4340, 2, 0, 5, 3, -1, -1, + 2, "mul", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_MVN, 0x43c0, 2, 0, 5, 3, -1, -1, + 2, "mvn", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_NEG, 0x4240, 2, 0, 5, 3, -1, -1, + 2, "neg", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_ORR, 0x4300, 2, 0, 5, 3, -1, -1, + 2, "orr", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_POP, 0xbc00, 8, 0, -1, -1, -1, -1, + 1, "pop", "<!0R>"), + ENCODING_MAP(ARMV5TE_PUSH, 0xb400, 8, 0, -1, -1, -1, -1, + 1, "push", "<!0R>"), + ENCODING_MAP(ARMV5TE_ROR, 0x41c0, 2, 0, 5, 3, -1, -1, + 2, "ror", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_SBC, 0x4180, 2, 0, 5, 3, -1, -1, + 2, "sbc", "r!0d, r!1d"), + ENCODING_MAP(ARMV5TE_STMIA, 0xc000, 10, 8, 7, 0, -1, -1, + 2, "stmia", "r!0d!!, <!1R>"), + ENCODING_MAP(ARMV5TE_STR_RRI5, 0x6000, 2, 0, 5, 3, 10, 6, + 3, "str", "r!0d, [r!1d, #!2E]"), + ENCODING_MAP(ARMV5TE_STR_RRR, 0x5000, 2, 0, 5, 3, 8, 6, + 3, "str", "r!0d, [r!1d, r!2d]"), + ENCODING_MAP(ARMV5TE_STR_SP_REL, 0x9000, 10, 8, 7, 0, -1, -1, + 2, "str", "r!0d, [sp, #!1E]"), + ENCODING_MAP(ARMV5TE_STRB_RRI5, 0x7000, 2, 0, 5, 3, 10, 6, + 3, "strb", "r!0d, [r!1d, #!2d]"), + ENCODING_MAP(ARMV5TE_STRB_RRR, 0x5400, 2, 0, 5, 3, 8, 6, + 3, "strb", "r!0d, [r!1d, r!2d]"), + ENCODING_MAP(ARMV5TE_STRH_RRI5, 0x8000, 2, 0, 5, 3, 10, 6, + 3, "strh", "r!0d, [r!1d, #!2F]"), + ENCODING_MAP(ARMV5TE_STRH_RRR, 0x5200, 2, 0, 5, 3, 8, 6, + 3, "strh", "r!0d, [r!1d, r!2d]"), + ENCODING_MAP(ARMV5TE_SUB_RRI3, 0x1e00, 2, 0, 5, 3, 8, 6, + 3, "sub", "r!0d, r!1d, #!2d]"), + ENCODING_MAP(ARMV5TE_SUB_RI8, 0x3800, 10, 8, 7, 0, -1, -1, + 2, "sub", "r!0d, #!1d"), + ENCODING_MAP(ARMV5TE_SUB_RRR, 0x1a00, 2, 0, 5, 3, 8, 6, + 3, "sub", "r!0d, r!1d, r!2d"), + ENCODING_MAP(ARMV5TE_SUB_SPI7, 0xb080, 6, 0, -1, -1, -1, -1, + 1, "sub", "sp, #!0d"), + ENCODING_MAP(ARMV5TE_SWI, 0xdf00, 7, 0, -1, -1, -1, -1, + 1, "swi", "!0d"), + ENCODING_MAP(ARMV5TE_TST, 0x4200, 2, 0, 5, 3, -1, -1, + 1, "tst", "r!0d, r!1d"), +}; + +#define PADDING_MOV_R0_R0 0x1C00 + +/* Write the numbers in the literal pool to the codegen stream */ +static void writeDataContent(CompilationUnit *cUnit) +{ + int *dataPtr = (int *) (cUnit->codeBuffer + cUnit->dataOffset); + Armv5teLIR *dataLIR = (Armv5teLIR *) cUnit->wordList; + while (dataLIR) { + *dataPtr++ = dataLIR->operands[0]; + dataLIR = NEXT_LIR(dataLIR); + } +} + +/* Return TRUE if error happens */ +static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr) +{ + short *bufferAddr = (short *) cUnit->codeBuffer; + Armv5teLIR *lir; + bool retry = false; + + for (lir = (Armv5teLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) { + if (lir->opCode < 0) { + if ((lir->opCode == ARMV5TE_PSEUDO_ALIGN4) && + (lir->operands[0] == 1) && + !retry) { + *bufferAddr++ = PADDING_MOV_R0_R0; + } + continue; + } + + if (lir->opCode == ARMV5TE_LDR_PC_REL || + lir->opCode == ARMV5TE_ADD_PC_REL) { + Armv5teLIR *lirTarget = (Armv5teLIR *) lir->generic.target; + intptr_t pc = (lir->generic.offset + 4) & ~3; + intptr_t target = lirTarget->generic.offset; + int delta = target - pc; + if (delta & 0x3) { + LOGE("PC-rel distance is not multiples of 4: %d\n", delta); + dvmAbort(); + } + lir->operands[1] = delta >> 2; + } else if (lir->opCode == ARMV5TE_B_COND) { + Armv5teLIR *targetLIR = (Armv5teLIR *) lir->generic.target; + intptr_t pc = lir->generic.offset + 4; + intptr_t target = targetLIR->generic.offset; + int delta = target - pc; + if (delta > 254 || delta < -256) { + /* Pull in the PC reconstruction code inline */ + if (targetLIR->opCode == ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL){ + /* + * The original code is: + * + * bxx targetLIR + * origNextLir + * : + * : + * targetLIR (a PC reconstruction cell) + * : + * lastLIR (should be a unconditional branch) + * + * The distance from bxx to targetLIR is too far, so we want + * to rearrange the code to be: + * + * bxx targetLIR + * branchoverLIR to origNextLir + * targetLIR (a PC reconstruction cell) + * : + * lastLIR (should be a unconditional branch) + * origNextLir + * + * Although doing so adds a unconditional branchover + * instruction, it can be predicted for free by ARM so + * the penalty should be minimal. + */ + Armv5teLIR *pcrLIR = targetLIR; + Armv5teLIR *lastLIR = pcrLIR; + Armv5teLIR *origNextLIR = NEXT_LIR(lir); + + /* + * Find out the last instruction in the PC reconstruction + * cell + */ + while (lastLIR->opCode != ARMV5TE_B_UNCOND) { + lastLIR = NEXT_LIR(lastLIR); + } + + /* Yank out the PCR code */ + PREV_LIR_LVALUE(NEXT_LIR(lastLIR)) = + (LIR *) PREV_LIR(targetLIR); + NEXT_LIR_LVALUE(PREV_LIR(targetLIR)) = + (LIR *) NEXT_LIR(lastLIR); + + /* Create the branch over instruction */ + Armv5teLIR *branchoverLIR = + dvmCompilerNew(sizeof(Armv5teLIR), true); + branchoverLIR->opCode = ARMV5TE_B_UNCOND; + branchoverLIR->generic.target = (LIR *) origNextLIR; + + /* Reconnect the instructions */ + NEXT_LIR_LVALUE(lir) = (LIR *) branchoverLIR; + PREV_LIR_LVALUE(branchoverLIR) = (LIR *) lir; + + NEXT_LIR_LVALUE(branchoverLIR) = (LIR *) targetLIR; + PREV_LIR_LVALUE(targetLIR) = (LIR *) branchoverLIR; + + NEXT_LIR_LVALUE(lastLIR) = (LIR *) origNextLIR; + PREV_LIR_LVALUE(origNextLIR) = (LIR *) lastLIR; + + retry = true; + continue; + } else { + LOGE("Conditional branch distance out of range: %d\n", + delta); + dvmAbort(); + } + } + lir->operands[0] = delta >> 1; + } else if (lir->opCode == ARMV5TE_B_UNCOND) { + Armv5teLIR *targetLIR = (Armv5teLIR *) lir->generic.target; + intptr_t pc = lir->generic.offset + 4; + intptr_t target = targetLIR->generic.offset; + int delta = target - pc; + if (delta > 2046 || delta < -2048) { + LOGE("Unconditional branch distance out of range: %d\n", delta); + dvmAbort(); + } + lir->operands[0] = delta >> 1; + } else if (lir->opCode == ARMV5TE_BLX_1) { + assert(NEXT_LIR(lir)->opCode == ARMV5TE_BLX_2); + /* curPC is Thumb */ + intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3; + intptr_t target = lir->operands[1]; + + /* Match bit[1] in target with base */ + if (curPC & 0x2) { + target |= 0x2; + } + int delta = target - curPC; + assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2))); + + lir->operands[0] = (delta >> 12) & 0x7ff; + NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff; + } + + /* + * The code offset will be recalculated, just continue to check if + * there are other places where code will be rescheduled and do not + * write to the output buffer + */ + if (retry) { + continue; + } + Armv5teEncodingMap *encoder = &EncodingMap[lir->opCode]; + short bits = encoder->skeleton; + int i; + for (i = 0; i < 3; i++) { + short value; + if (encoder->fieldLoc[i].end != -1) { + value = (lir->operands[i] << encoder->fieldLoc[i].start) & + ((1 << (encoder->fieldLoc[i].end + 1)) - 1); + bits |= value; + + } + } + *bufferAddr++ = bits; + } + return retry; +} + +/* + * Go over each instruction in the list and calculate the offset from the top + * before sending them off to the assembler. If out-of-range branch distance is + * seen rearrange the instructions a bit to correct it. + */ +void dvmCompilerAssembleLIR(CompilationUnit *cUnit) +{ + LIR *lir; + Armv5teLIR *armLIR; + int offset; + int i; + +retry: + for (armLIR = (Armv5teLIR *) cUnit->firstLIRInsn, offset = 0; + armLIR; + armLIR = NEXT_LIR(armLIR)) { + armLIR->generic.offset = offset; + if (armLIR->opCode >= 0) { + offset += 2; + } else if (armLIR->opCode == ARMV5TE_PSEUDO_ALIGN4) { + if (offset & 0x2) { + offset += 2; + armLIR->operands[0] = 1; + } else { + armLIR->operands[0] = 0; + } + } + /* Pseudo opcodes don't consume space */ + } + + /* Const values have to be word aligned */ + offset = ((offset + 3) >> 2) << 2; + + cUnit->dataOffset = offset; + + for (lir = cUnit->wordList; lir; lir = lir->next) { + lir->offset = offset; + offset += 4; + } + + cUnit->totalSize = offset; + + if (gDvmJit.codeCacheByteUsed + offset > CODE_CACHE_SIZE) { + gDvmJit.codeCacheFull = true; + cUnit->baseAddr = NULL; + return; + } + cUnit->codeBuffer = dvmCompilerNew(offset, true); + if (cUnit->codeBuffer == NULL) { + LOGE("Code buffer allocation failure\n"); + cUnit->baseAddr = NULL; + return; + } + + bool needRetry = assembleInstructions( + cUnit, (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed); + + if (needRetry) + goto retry; + + writeDataContent(cUnit); + + cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed; + gDvmJit.codeCacheByteUsed += offset; + + + /* Install the compilation */ + memcpy(cUnit->baseAddr, cUnit->codeBuffer, offset); + gDvmJit.numCompilations++; + + /* Flush dcache and invalidate the icache to maintain coherence */ + cacheflush((intptr_t) cUnit->baseAddr, + (intptr_t) (cUnit->baseAddr + offset), 0); +} + +/* + * Perform translation chain operation. + * For ARM, we'll use a pair of thumb instructions to generate + * an unconditional chaining branch of up to 4MB in distance. + * Use a BL, though we don't really need the link. The format is + * 111HHooooooooooo + * Where HH is 10 for the 1st inst, and 11 for the second and + * the "o" field is each instruction's 11-bit contribution to the + * 22-bit branch offset. + * TUNING: use a single-instruction variant if it reaches. + */ +void* dvmJitChain(void* tgtAddr, u4* branchAddr) +{ + int baseAddr = (u4) branchAddr + 4; + int branchOffset = (int) tgtAddr - baseAddr; + u4 thumb1; + u4 thumb2; + u4 newInst; + + assert((branchOffset >= -(1<<22)) && (branchOffset <= ((1<<22)-2))); + + gDvmJit.translationChains++; + + COMPILER_TRACE_CHAINING( + LOGD("Jit Runtime: chaining 0x%x to 0x%x\n", + (int) branchAddr, (int) tgtAddr & -2)); + if ((branchOffset < -2048) | (branchOffset > 2046)) { + thumb1 = (0xf000 | ((branchOffset>>12) & 0x7ff)); + thumb2 = (0xf800 | ((branchOffset>> 1) & 0x7ff)); + } else { + thumb1 = (0xe000 | ((branchOffset>> 1) & 0x7ff)); + thumb2 = 0x4300; /* nop -> or r0, r0 */ + } + + newInst = thumb2<<16 | thumb1; + *branchAddr = newInst; + cacheflush((intptr_t) branchAddr, (intptr_t) branchAddr + 4, 0); + + return tgtAddr; +} |