📄 jitemitter_cpu.c
字号:
/* * Emit a 32 bit value (aka .word). */voidCVMJITemitWord(CVMJITCompilationContext *con, CVMInt32 wordVal){ CVMJITcsSetEmitInPlace(con); emitInstruction(con, wordVal); CVMJITcsClearEmitInPlace(con); CVMtraceJITCodegenExec({ printPC(con); CVMconsolePrintf(" .word %d", wordVal); }); CVMJITdumpCodegenComments(con);}voidCVMCPUemitNop(CVMJITCompilationContext *con){ CVMJITcsSetEmitInPlace(con); emitInstruction(con, CVMCPU_NOP_INSTRUCTION); CVMJITcsClearEmitInPlace(con); CVMtraceJITCodegenExec({ printPC(con); CVMconsolePrintf(" nop"); }); CVMJITdumpCodegenComments(con);}/* * Binary ALU operation w/ 16-bit constant, always using two instructions. */static voidemitBinaryALUConstant16Conditional(CVMJITCompilationContext* con, int opcode, int destReg, int sourceReg, CVMUint32 constant, CVMBool setcc, CVMCPUCondCode condCode){ /* Scaled components of the 16-bit constant */ CVMUint32 constantHi = constant & 0xff00; CVMUint32 constantLo = constant & 0x00ff; CVMassert(constant < 0x10000); /* Better fit in 16-bits */ CVMassert(opcode == CVMCPU_BIC_OPCODE || opcode == CVMCPU_OR_OPCODE || opcode == CVMCPU_XOR_OPCODE || opcode == CVMCPU_ADD_OPCODE || opcode == CVMCPU_SUB_OPCODE); /* Encode as two instructions */ CVMJITcsPushSourceRegister(con, sourceReg); CVMCPUemitBinaryALUConditional(con, opcode, destReg, sourceReg, CVMARMalurhsEncodeConstantToken(con, constantLo), setcc, condCode); CVMCPUemitBinaryALUConditional(con, opcode, destReg, destReg, CVMARMalurhsEncodeConstantToken(con, constantHi), setcc, condCode);}#ifdef CVMCPU_HAS_CP_REG/* Purpose: Set up constant pool base register */voidCVMCPUemitLoadConstantPoolBaseRegister(CVMJITCompilationContext *con){ CVMInt32 offset; /* * Load the constant pool base register. It can be as far * as 64k-4 away, so it will take two adds to do this. Note * that even if it could be done in one, we already reserved * two instruction for it, so we might as well just use them * both. */ offset = con->target.cpLogicalPC - CVMJITcbufGetLogicalPC(con) - 8; CVMJITprintCodegenComment(("setup cp base register")); aluConstant16ScaledConditional(con, CVMCPU_ADD_OPCODE, CVMCPU_CP_REG, CVMARM_PC, offset, 0, CVMCPU_COND_AL); /* * Save the constant pool base register into the frame so it can * be restored if we invoke another method. */ CVMJITaddCodegenComment((con, "save to frame->cpBaseRegX")); CVMassert(CVMCPUmemspecIsEncodableAsImmediate( CVMoffsetof(CVMCompiledFrame, cpBaseRegX))); CVMCPUemitMemoryReferenceImmediate( con, CVMCPU_STR32_OPCODE, CVMCPU_CP_REG, CVMCPU_JFP_REG, CVMoffsetof(CVMCompiledFrame, cpBaseRegX));}#endif /* CVMCPU_HAS_CP_REG *//* Purpose: Add/sub a 16-bits constant scaled by 2^scale. Called by * method prologue and patch emission routines. * NOTE: CVMCPUemitAddConstant16Scaled should not rely on regman * states because the regman context used to emit the method * prologue is gone at the patching time. * NOTE: CVMCPUemitALUConstant16Scaled must always emit the same * number of instructions, no matter what constant or scale * is passed to it. */voidCVMCPUemitALUConstant16Scaled(CVMJITCompilationContext *con, int opcode, int destRegID, int srcRegID, CVMUint32 constant, int scale){ CVMUint32 value = constant << scale; CVMassert(opcode == CVMCPU_ADD_OPCODE || opcode == CVMCPU_SUB_OPCODE); if (CVMCPUalurhsIsEncodableAsImmediate(opcode, value)) { /* Encode in one instruction */ CVMCPUemitBinaryALU(con, opcode, destRegID, srcRegID, CVMARMalurhsEncodeConstantToken(con, value), CVMJIT_NOSETCC); } else { /* The only time this would happen is if there are about 240+ * words of locals, so it's ok to just not compile this method. */ CVMJITerror(con, CANNOT_COMPILE, "too many locals"); }}/* * Purpose: Stack limit check at the start of each method, corresponding to: * * ldr a4, [sp, #OFFSET_CVMCCExecEnv_stackChunkEnd]; * str lr, [JFP, #OFFSET_CVMCCExecEnv_pcX]; * cmp a4, a2; * bls letInterpreterDoInvoke; * * Schedule the lr flush to give 'a4' time to "settle". */voidCVMCPUemitStackLimitCheckAndStoreReturnAddr(CVMJITCompilationContext* con){ CVMJITaddCodegenComment((con, "Store LR into frame")); CVMassert(CVMCPUmemspecIsEncodableAsImmediate( CVMoffsetof(CVMCompiledFrame, pcX))); CVMCPUemitMemoryReferenceImmediate(con, CVMCPU_STR32_OPCODE, CVMARM_LR, CVMCPU_JFP_REG, CVMoffsetof(CVMCompiledFrame, pcX)); CVMCPUemitCompareRegister(con, CVMCPU_CMP_OPCODE, CVMCPU_COND_LS, CVMCPU_ARG4_REG, CVMCPU_ARG2_REG); CVMJITaddCodegenComment((con, "letInterpreterDoInvoke"));#ifdef CVM_JIT_COPY_CCMCODE_TO_CODECACHE CVMCPUemitBranch(con, CVMCCMcodeCacheCopyHelperOffset(con, CVMCCMletInterpreterDoInvokeWithoutFlushRetAddr), CVMCPU_COND_LS);#else /* * This accesses the CP, and such is incompatible with CP_REG code * (can't access constant pool in prologue) */#ifdef CVMCPU_HAS_CP_REG#error "Cannot support 'bls letInterpreterDoInvoke' when glue not in code cache and doing CP register setups"#else /* load the new pc from memory */ CVMCPUemitLoadConstantConditional(con, CVMARM_PC, (CVMInt32)CVMCCMletInterpreterDoInvokeWithoutFlushRetAddr, CVMCPU_COND_LS);#endif#endif}/* * Purpose: Emits code to invoke method through MB. * MB is already in CVMCPU_ARG1_REG. */voidCVMCPUemitInvokeMethod(CVMJITCompilationContext* con){ CVMUint32 off; /* MOV LR, PC */ CVMJITaddCodegenComment((con, "setup return address")); CVMJITcsSetEmitInPlace(con); CVMCPUemitMoveRegister(con, CVMCPU_MOV_OPCODE, CVMARM_LR, CVMARM_PC, CVMJIT_NOSETCC); /* LDR PC, [MB + #OFFSET_JITInvoker] */ CVMJITaddCodegenComment((con, "call method through mb")); off = CVMoffsetof(CVMMethodBlock, jitInvokerX); CVMCPUemitMemoryReferenceImmediate(con, CVMCPU_LDR32_OPCODE, CVMARM_PC, CVMCPU_ARG1_REG, off); CVMJITcsClearEmitInPlace(con); CVMJITcsBeginBlock(con);}/* * Move the JSR return address into regno. This is a no-op on * cpu's where the CVMCPU_JSR_RETURN_ADDRESS_SET == LR. */voidCVMCPUemitLoadReturnAddress(CVMJITCompilationContext* con, int regno){ CVMassert(regno == CVMARM_LR);}/* * Branch to the address in the specified register. */voidCVMCPUemitRegisterBranch(CVMJITCompilationContext* con, int regno){ CVMJITcsSetEmitInPlace(con); CVMCPUemitMoveRegister(con, CVMCPU_MOV_OPCODE, CVMARM_PC, regno, CVMJIT_NOSETCC); CVMJITcsClearEmitInPlace(con);}/* * Do a branch for a tableswitch. We need to branch into the dispatch * table. The table entry for index 0 will be generated right after * any instructions that are generated here.. */voidCVMCPUemitTableSwitchBranch(CVMJITCompilationContext* con, int indexRegNo){ /* * Since on arm the pc is already offset by 8, we just need to add * key*4 to pc and then pad with a nop so things line up right. */ CVMCPUALURhsToken token; token = CVMARMalurhsEncodeShiftByConstantToken(con, indexRegNo, CVMCPU_SLL_OPCODE, 2); CVMJITcsSetEmitInPlace(con); CVMCPUemitBinaryALU(con, CVMCPU_ADD_OPCODE, CVMARM_PC, CVMARM_PC, token, CVMJIT_NOSETCC); CVMJITcsClearEmitInPlace(con); CVMCPUemitNop(con);}voidCVMCPUemitPopFrame(CVMJITCompilationContext* con, int resultSize){ CVMUint32 offset; /* offset from JFP for new JSP */ CVMUint32 rotate; CVMUint32 base; /* We want to set JSP to the address of the locals + the resultSize */ offset = (con->numberLocalWords - resultSize) * sizeof(CVMJavaVal32); if (CVMARMmode1EncodeImmediate(offset, &base, &rotate)) { CVMJITcsSetDestRegister(con, CVMCPU_JSP_REG); CVMJITcsPushSourceRegister(con, CVMCPU_JFP_REG); /* If it's encodable, we quickly emit the instruction: */ emitInstruction(con, ARM_MAKE_CONDCODE_BITS(CVMCPU_COND_AL) | (CVMUint32)CVMCPU_SUB_OPCODE | CVMCPU_JFP_REG << 16 | CVMCPU_JSP_REG << 12 | CVMARM_MODE1_CONSTANT | rotate << 8 | base); CVMtraceJITCodegenExec({ printPC(con); CVMconsolePrintf(" sub JSP, JFP, #%d", offset); }); CVMJITdumpCodegenComments(con); } else { /* Else, we make use of all the other emitter functions that are already available for emitting and tracking the pieces we need: */ CVMRMResource *offsetRes; CVMUint32 offsetReg; /* Load the offset as a constant into a register: */ offsetRes = CVMRMgetResource(CVMRM_INT_REGS(con), CVMRM_ANY_SET, CVMRM_EMPTY_SET, 1); offsetReg = CVMRMgetRegisterNumber(offsetRes); CVMCPUemitLoadConstant(con, offsetReg, offset); /* Pop the frame: */ CVMCPUemitBinaryALURegister(con, CVMCPU_SUB_OPCODE, CVMCPU_JSP_REG, CVMCPU_JFP_REG, offsetReg, CVMJIT_NOSETCC); CVMRMunpinResource(CVMRM_INT_REGS(con), offsetRes); }}#ifdef CVM_JIT_PATCHED_METHOD_INVOCATIONS/* * Patch branch instruction at location "instrAddr" to branch to offset * "offset" from "instrAddr". */voidCVMCPUpatchBranchInstruction(int offset, CVMUint8* instrAddr){ CVMCPUInstruction branch; /* There better already be an unconditional bl at this address */ CVMassert((*(CVMUint32*)instrAddr & 0xff000000) == (ARM_BL_OPCODE | ARM_MAKE_CONDCODE_BITS(CVMCPU_COND_AL))); branch = CVMARMgetBranchInstruction(CVMCPU_COND_AL, offset, CVM_TRUE); *((CVMCPUInstruction*)instrAddr) = branch;}#endif/* * Make a PC-relative branch or branch-and-link instruction */CVMCPUInstructionCVMARMgetBranchInstruction(CVMCPUCondCode condCode, int offset, CVMBool link){ CVMUint32 opcode = (link ? ARM_BL_OPCODE : ARM_B_OPCODE); int realoffset = (offset - 8) >> 2; /* adjust by 8 on ARM */ CVMassert((realoffset & 0xff800000) == 0 || (realoffset & 0xff800000) == 0xff800000); return (ARM_MAKE_CONDCODE_BITS(condCode) | opcode | ((CVMUint32)realoffset & 0x00ffffff));}/* Purpose: Emits a branch or branch and link instruction. */voidCVMARMemitBranch(CVMJITCompilationContext* con, int logicalPC, CVMCPUCondCode condCode, CVMBool link, CVMJITFixupElement** fixupList){ CVMUint32 branchInstruction; CVMJITcsSetStatusInstruction(con, condCode); CVMJITcsSetBranchInstruction(con);#ifdef IAI_CS_EXCEPTION_ENHANCEMENT2 CVMJITcsSetEmitInPlaceWithBufSizeAdjust(con, \ CVMJITcsIsArrayIndexOutofBoundsBranch(con), sizeof(CVMCPUInstruction));#else CVMJITcsSetEmitInPlace(con);#endif if (fixupList != NULL) { CVMJITfixupAddElement(con, fixupList, CVMJITcbufGetLogicalPC(con)); } branchInstruction = CVMARMgetBranchInstruction(condCode, logicalPC - CVMJITcbufGetLogicalPC(con), link); emitInstruction(con, branchInstruction); CVMJITstatsRecordInc(con, CVMJIT_STATS_BRANCHES); CVMtraceJITCodegenExec({ printPC(con); CVMconsolePrintf(" %s%s PC=(%d)", link ? "bl" : "b", conditions[condCode], logicalPC); }); CVMJITcsClearEmitInPlace(con); CVMJITdumpCodegenComments(con);}/* Purpose: Emits instructions to do the specified conditional 32 bit unary ALU operation. */voidCVMCPUemitUnaryALUConditional(CVMJITCompilationContext *con, int opcode, int destRegID, int srcRegID, CVMBool setcc, CVMCPUCondCode condCode){ switch (opcode) { case CVMCPU_NOT_OPCODE: /* reg32 = (reg32 == 0)?1:0. */ CVMassert(condCode = CVMCPU_COND_AL); CVMCPUemitCompareConstant(con, CVMCPU_CMP_OPCODE, CVMCPU_COND_AL, srcRegID, 0); CVMCPUemitLoadConstantConditional(con, destRegID, 0, CVMCPU_COND_NE); CVMCPUemitLoadConstantConditional(con, destRegID, 1, CVMCPU_COND_EQ); break; case CVMCPU_INT2BIT_OPCODE: /* reg32 = (reg32 != 0)?1:0. */ CVMassert(condCode = CVMCPU_COND_AL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -