1 /*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * This file contains arm-specific codegen factory support.
19 * It is included by
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25 /*
26 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
27 * satisfies.
28 */
genRegImmCheck(CompilationUnit * cUnit,ArmConditionCode cond,int reg,int checkValue,int dOffset,TGT_LIR * pcrLabel)29 static TGT_LIR *genRegImmCheck(CompilationUnit *cUnit,
30 ArmConditionCode cond, int reg,
31 int checkValue, int dOffset,
32 TGT_LIR *pcrLabel)
33 {
34 TGT_LIR *branch = genCmpImmBranch(cUnit, cond, reg, checkValue);
35 if (cUnit->jitMode == kJitMethod) {
36 BasicBlock *bb = cUnit->curBlock;
37 if (bb->taken) {
38 ArmLIR *exceptionLabel = (ArmLIR *) cUnit->blockLabelList;
39 exceptionLabel += bb->taken->id;
40 branch->generic.target = (LIR *) exceptionLabel;
41 return exceptionLabel;
42 } else {
43 ALOGE("Catch blocks not handled yet");
44 dvmAbort();
45 return NULL;
46 }
47 } else {
48 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
49 }
50 }
51
52 /*
53 * Perform null-check on a register. sReg is the ssa register being checked,
54 * and mReg is the machine register holding the actual value. If internal state
55 * indicates that sReg has been checked before the check request is ignored.
56 */
genNullCheck(CompilationUnit * cUnit,int sReg,int mReg,int dOffset,TGT_LIR * pcrLabel)57 static TGT_LIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
58 int dOffset, TGT_LIR *pcrLabel)
59 {
60 /* This particular Dalvik register has been null-checked */
61 if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
62 return pcrLabel;
63 }
64 dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
65 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
66 }
67
68 /*
69 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
70 * satisfies.
71 */
genRegRegCheck(CompilationUnit * cUnit,ArmConditionCode cond,int reg1,int reg2,int dOffset,TGT_LIR * pcrLabel)72 static TGT_LIR *genRegRegCheck(CompilationUnit *cUnit,
73 ArmConditionCode cond,
74 int reg1, int reg2, int dOffset,
75 TGT_LIR *pcrLabel)
76 {
77 TGT_LIR *res;
78 res = opRegReg(cUnit, kOpCmp, reg1, reg2);
79 TGT_LIR *branch = opCondBranch(cUnit, cond);
80 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
81 return res;
82 }
83
84 /*
85 * Perform zero-check on a register. Similar to genNullCheck but the value being
86 * checked does not have a corresponding Dalvik register.
87 */
genZeroCheck(CompilationUnit * cUnit,int mReg,int dOffset,TGT_LIR * pcrLabel)88 static TGT_LIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
89 int dOffset, TGT_LIR *pcrLabel)
90 {
91 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
92 }
93
94 /* Perform bound check on two registers */
genBoundsCheck(CompilationUnit * cUnit,int rIndex,int rBound,int dOffset,TGT_LIR * pcrLabel)95 static TGT_LIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
96 int rBound, int dOffset, TGT_LIR *pcrLabel)
97 {
98 return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
99 pcrLabel);
100 }
101
102 /*
103 * Jump to the out-of-line handler in ARM mode to finish executing the
104 * remaining of more complex instructions.
105 */
genDispatchToHandler(CompilationUnit * cUnit,TemplateOpcode opcode)106 static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpcode opcode)
107 {
108 /*
109 * NOTE - In practice BLX only needs one operand, but since the assembler
110 * may abort itself and retry due to other out-of-range conditions we
111 * cannot really use operand[0] to store the absolute target address since
112 * it may get clobbered by the final relative offset. Therefore,
113 * we fake BLX_1 is a two operand instruction and the absolute target
114 * address is stored in operand[1].
115 */
116 dvmCompilerClobberHandlerRegs(cUnit);
117 newLIR2(cUnit, kThumbBlx1,
118 (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
119 (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
120 newLIR2(cUnit, kThumbBlx2,
121 (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
122 (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
123 }
124