blob: a6aafd126f99f7e8c2ce517599079732d1dee936 [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
2 * Copyright (C) 2009 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
Bill Buzbee50a6bf22009-07-08 13:08:04 -070017/*
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
Ben Cheng5d90c202009-11-22 23:31:11 -080027static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
28 int srcSize, int tgtSize)
29{
30 /*
31 * Don't optimize the register usage since it calls out to template
32 * functions
33 */
34 RegLocation rlSrc;
35 RegLocation rlDest;
Bill Buzbeec6f10662010-02-09 11:16:15 -080036 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
Ben Cheng5d90c202009-11-22 23:31:11 -080037 if (srcSize == 1) {
Bill Buzbeec6f10662010-02-09 11:16:15 -080038 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Ben Cheng5d90c202009-11-22 23:31:11 -080039 loadValueDirectFixed(cUnit, rlSrc, r0);
40 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -080041 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
Ben Cheng5d90c202009-11-22 23:31:11 -080042 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
43 }
44 loadConstant(cUnit, r2, (int)funct);
45 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -080046 dvmCompilerClobberCallRegs(cUnit);
Ben Cheng5d90c202009-11-22 23:31:11 -080047 if (tgtSize == 1) {
48 RegLocation rlResult;
Bill Buzbeec6f10662010-02-09 11:16:15 -080049 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
50 rlResult = dvmCompilerGetReturn(cUnit);
Ben Cheng5d90c202009-11-22 23:31:11 -080051 storeValue(cUnit, rlDest, rlResult);
52 } else {
53 RegLocation rlResult;
Bill Buzbeec6f10662010-02-09 11:16:15 -080054 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
55 rlResult = dvmCompilerGetReturnWide(cUnit);
Ben Cheng5d90c202009-11-22 23:31:11 -080056 storeValueWide(cUnit, rlDest, rlResult);
57 }
58 return false;
59}
Ben Chengba4fc8b2009-06-01 13:00:29 -070060
Ben Chengba4fc8b2009-06-01 13:00:29 -070061
Ben Cheng5d90c202009-11-22 23:31:11 -080062static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
63 RegLocation rlDest, RegLocation rlSrc1,
64 RegLocation rlSrc2)
65{
66 RegLocation rlResult;
67 void* funct;
68
69 /* TODO: use a proper include file to define these */
70 float __aeabi_fadd(float a, float b);
71 float __aeabi_fsub(float a, float b);
72 float __aeabi_fdiv(float a, float b);
73 float __aeabi_fmul(float a, float b);
74 float fmodf(float a, float b);
75
76 switch (mir->dalvikInsn.opCode) {
77 case OP_ADD_FLOAT_2ADDR:
78 case OP_ADD_FLOAT:
79 funct = (void*) __aeabi_fadd;
80 break;
81 case OP_SUB_FLOAT_2ADDR:
82 case OP_SUB_FLOAT:
83 funct = (void*) __aeabi_fsub;
84 break;
85 case OP_DIV_FLOAT_2ADDR:
86 case OP_DIV_FLOAT:
87 funct = (void*) __aeabi_fdiv;
88 break;
89 case OP_MUL_FLOAT_2ADDR:
90 case OP_MUL_FLOAT:
91 funct = (void*) __aeabi_fmul;
92 break;
93 case OP_REM_FLOAT_2ADDR:
94 case OP_REM_FLOAT:
95 funct = (void*) fmodf;
96 break;
97 case OP_NEG_FLOAT: {
98 genNegFloat(cUnit, rlDest, rlSrc1);
99 return false;
100 }
101 default:
102 return true;
103 }
Bill Buzbeec6f10662010-02-09 11:16:15 -0800104 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
Ben Cheng5d90c202009-11-22 23:31:11 -0800105 loadValueDirectFixed(cUnit, rlSrc1, r0);
106 loadValueDirectFixed(cUnit, rlSrc2, r1);
107 loadConstant(cUnit, r2, (int)funct);
108 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -0800109 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800110 rlResult = dvmCompilerGetReturn(cUnit);
Ben Cheng5d90c202009-11-22 23:31:11 -0800111 storeValue(cUnit, rlDest, rlResult);
112 return false;
113}
114
115static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
116 RegLocation rlDest, RegLocation rlSrc1,
117 RegLocation rlSrc2)
118{
119 RegLocation rlResult;
120 void* funct;
121
122 /* TODO: use a proper include file to define these */
123 double __aeabi_dadd(double a, double b);
124 double __aeabi_dsub(double a, double b);
125 double __aeabi_ddiv(double a, double b);
126 double __aeabi_dmul(double a, double b);
127 double fmod(double a, double b);
128
129 switch (mir->dalvikInsn.opCode) {
130 case OP_ADD_DOUBLE_2ADDR:
131 case OP_ADD_DOUBLE:
132 funct = (void*) __aeabi_dadd;
133 break;
134 case OP_SUB_DOUBLE_2ADDR:
135 case OP_SUB_DOUBLE:
136 funct = (void*) __aeabi_dsub;
137 break;
138 case OP_DIV_DOUBLE_2ADDR:
139 case OP_DIV_DOUBLE:
140 funct = (void*) __aeabi_ddiv;
141 break;
142 case OP_MUL_DOUBLE_2ADDR:
143 case OP_MUL_DOUBLE:
144 funct = (void*) __aeabi_dmul;
145 break;
146 case OP_REM_DOUBLE_2ADDR:
147 case OP_REM_DOUBLE:
148 funct = (void*) fmod;
149 break;
150 case OP_NEG_DOUBLE: {
151 genNegDouble(cUnit, rlDest, rlSrc1);
152 return false;
153 }
154 default:
155 return true;
156 }
Bill Buzbeec6f10662010-02-09 11:16:15 -0800157 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
Ben Cheng5d90c202009-11-22 23:31:11 -0800158 loadConstant(cUnit, rlr, (int)funct);
159 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
160 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
161 opReg(cUnit, kOpBlx, rlr);
Elliott Hughes6a555132010-02-25 15:41:42 -0800162 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800163 rlResult = dvmCompilerGetReturnWide(cUnit);
Ben Cheng5d90c202009-11-22 23:31:11 -0800164 storeValueWide(cUnit, rlDest, rlResult);
165 return false;
166}
167
168static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
169{
170 OpCode opCode = mir->dalvikInsn.opCode;
171
172 float __aeabi_i2f( int op1 );
173 int __aeabi_f2iz( float op1 );
174 float __aeabi_d2f( double op1 );
175 double __aeabi_f2d( float op1 );
176 double __aeabi_i2d( int op1 );
177 int __aeabi_d2iz( double op1 );
178 float __aeabi_l2f( long op1 );
179 double __aeabi_l2d( long op1 );
180 s8 dvmJitf2l( float op1 );
181 s8 dvmJitd2l( double op1 );
182
183 switch (opCode) {
184 case OP_INT_TO_FLOAT:
185 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
186 case OP_FLOAT_TO_INT:
187 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
188 case OP_DOUBLE_TO_FLOAT:
189 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
190 case OP_FLOAT_TO_DOUBLE:
191 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
192 case OP_INT_TO_DOUBLE:
193 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
194 case OP_DOUBLE_TO_INT:
195 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
196 case OP_FLOAT_TO_LONG:
197 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
198 case OP_LONG_TO_FLOAT:
199 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
200 case OP_DOUBLE_TO_LONG:
201 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
202 case OP_LONG_TO_DOUBLE:
203 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
204 default:
205 return true;
206 }
207 return false;
208}
Ben Chengba4fc8b2009-06-01 13:00:29 -0700209
Jeff Hao97319a82009-08-12 16:57:15 -0700210#if defined(WITH_SELF_VERIFICATION)
jeffhao9e45c0b2010-02-03 10:24:05 -0800211static void selfVerificationBranchInsert(LIR *currentLIR, ArmOpCode opCode,
212 int dest, int src1)
Jeff Hao97319a82009-08-12 16:57:15 -0700213{
jeffhao9e45c0b2010-02-03 10:24:05 -0800214 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
215 insn->opCode = opCode;
216 insn->operands[0] = dest;
217 insn->operands[1] = src1;
218 setupResourceMasks(insn);
219 dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn);
Jeff Hao97319a82009-08-12 16:57:15 -0700220}
221
jeffhao9e45c0b2010-02-03 10:24:05 -0800222static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
Jeff Hao97319a82009-08-12 16:57:15 -0700223{
jeffhao9e45c0b2010-02-03 10:24:05 -0800224 ArmLIR *thisLIR;
225 ArmLIR *branchLIR = dvmCompilerNew(sizeof(ArmLIR), true);
226 TemplateOpCode opCode = TEMPLATE_MEM_OP_DECODE;
Jeff Hao97319a82009-08-12 16:57:15 -0700227
jeffhao9e45c0b2010-02-03 10:24:05 -0800228 for (thisLIR = (ArmLIR *) cUnit->firstLIRInsn;
229 thisLIR != (ArmLIR *) cUnit->lastLIRInsn;
230 thisLIR = NEXT_LIR(thisLIR)) {
231 if (thisLIR->branchInsertSV) {
232 /* Branch to mem op decode template */
233 selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1,
234 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
235 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
236 selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2,
237 (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
238 (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
Jeff Hao97319a82009-08-12 16:57:15 -0700239 }
240 }
Jeff Hao97319a82009-08-12 16:57:15 -0700241}
Jeff Hao97319a82009-08-12 16:57:15 -0700242#endif
243
Ben Chengba4fc8b2009-06-01 13:00:29 -0700244/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700245static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
246 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700247{
Bill Buzbee1465db52009-09-23 17:17:35 -0700248 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700249 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
250}
251
252/* Load a wide field from an object instance */
253static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
254{
255 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800256 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
257 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -0700258 RegLocation rlResult;
259 rlObj = loadValue(cUnit, rlObj, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800260 int regPtr = dvmCompilerAllocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700261
Bill Buzbee1465db52009-09-23 17:17:35 -0700262 assert(rlDest.wide);
Ben Chenge9695e52009-06-16 16:11:47 -0700263
Bill Buzbee1465db52009-09-23 17:17:35 -0700264 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
265 NULL);/* null object? */
266 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800267 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
jeffhao9e45c0b2010-02-03 10:24:05 -0800268#if defined(WITH_SELF_VERIFICATION)
269 cUnit->heapMemOp = true;
270#endif
Bill Buzbee1465db52009-09-23 17:17:35 -0700271 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
jeffhao9e45c0b2010-02-03 10:24:05 -0800272#if defined(WITH_SELF_VERIFICATION)
273 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -0700274#endif
Bill Buzbeec6f10662010-02-09 11:16:15 -0800275 dvmCompilerFreeTemp(cUnit, regPtr);
Bill Buzbee1465db52009-09-23 17:17:35 -0700276 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700277}
278
279/* Store a wide field to an object instance */
280static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
281{
282 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800283 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
284 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
Bill Buzbee1465db52009-09-23 17:17:35 -0700285 rlObj = loadValue(cUnit, rlObj, kCoreReg);
286 int regPtr;
287 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
288 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
289 NULL);/* null object? */
Bill Buzbeec6f10662010-02-09 11:16:15 -0800290 regPtr = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700291 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -0800292#if defined(WITH_SELF_VERIFICATION)
293 cUnit->heapMemOp = true;
294#endif
Bill Buzbee1465db52009-09-23 17:17:35 -0700295 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
jeffhao9e45c0b2010-02-03 10:24:05 -0800296#if defined(WITH_SELF_VERIFICATION)
297 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -0700298#endif
Bill Buzbeec6f10662010-02-09 11:16:15 -0800299 dvmCompilerFreeTemp(cUnit, regPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700300}
301
302/*
303 * Load a field from an object instance
304 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700305 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700306static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700307 int fieldOffset)
308{
Bill Buzbee1465db52009-09-23 17:17:35 -0700309 int regPtr;
310 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700311 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800312 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
313 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700314 rlObj = loadValue(cUnit, rlObj, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800315 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700316 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
317 NULL);/* null object? */
jeffhao9e45c0b2010-02-03 10:24:05 -0800318#if defined(WITH_SELF_VERIFICATION)
319 cUnit->heapMemOp = true;
320#endif
Ben Cheng5d90c202009-11-22 23:31:11 -0800321 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
322 size, rlObj.sRegLow);
jeffhao9e45c0b2010-02-03 10:24:05 -0800323#if defined(WITH_SELF_VERIFICATION)
324 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -0700325#endif
Bill Buzbee1465db52009-09-23 17:17:35 -0700326 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700327}
328
329/*
330 * Store a field to an object instance
331 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700332 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700333static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700334 int fieldOffset)
335{
336 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800337 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
338 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -0700339 rlObj = loadValue(cUnit, rlObj, kCoreReg);
340 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
341 int regPtr;
342 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
343 NULL);/* null object? */
jeffhao9e45c0b2010-02-03 10:24:05 -0800344#if defined(WITH_SELF_VERIFICATION)
345 cUnit->heapMemOp = true;
346#endif
Bill Buzbee1465db52009-09-23 17:17:35 -0700347 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
jeffhao9e45c0b2010-02-03 10:24:05 -0800348#if defined(WITH_SELF_VERIFICATION)
349 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -0700350#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700351}
352
353
Ben Chengba4fc8b2009-06-01 13:00:29 -0700354/*
355 * Generate array load
Ben Chengba4fc8b2009-06-01 13:00:29 -0700356 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700357static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Bill Buzbee1465db52009-09-23 17:17:35 -0700358 RegLocation rlArray, RegLocation rlIndex,
359 RegLocation rlDest, int scale)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700360{
361 int lenOffset = offsetof(ArrayObject, length);
362 int dataOffset = offsetof(ArrayObject, contents);
Bill Buzbee1465db52009-09-23 17:17:35 -0700363 RegLocation rlResult;
364 rlArray = loadValue(cUnit, rlArray, kCoreReg);
365 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
366 int regPtr;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700367
368 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -0700369 ArmLIR * pcrLabel = NULL;
370
371 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700372 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
373 rlArray.lowReg, mir->offset, NULL);
Ben Cheng4238ec22009-08-24 16:32:22 -0700374 }
375
Bill Buzbeec6f10662010-02-09 11:16:15 -0800376 regPtr = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700377
Ben Cheng4238ec22009-08-24 16:32:22 -0700378 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800379 int regLen = dvmCompilerAllocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -0700380 /* Get len */
Bill Buzbee1465db52009-09-23 17:17:35 -0700381 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
382 /* regPtr -> array data */
383 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
384 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
385 pcrLabel);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800386 dvmCompilerFreeTemp(cUnit, regLen);
Ben Cheng4238ec22009-08-24 16:32:22 -0700387 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700388 /* regPtr -> array data */
389 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -0700390 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700391 if ((size == kLong) || (size == kDouble)) {
392 if (scale) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800393 int rNewIndex = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700394 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
395 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800396 dvmCompilerFreeTemp(cUnit, rNewIndex);
Bill Buzbee1465db52009-09-23 17:17:35 -0700397 } else {
398 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
399 }
Bill Buzbeec6f10662010-02-09 11:16:15 -0800400 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
jeffhao9e45c0b2010-02-03 10:24:05 -0800401#if defined(WITH_SELF_VERIFICATION)
402 cUnit->heapMemOp = true;
403#endif
Bill Buzbee1465db52009-09-23 17:17:35 -0700404 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
jeffhao9e45c0b2010-02-03 10:24:05 -0800405#if defined(WITH_SELF_VERIFICATION)
406 cUnit->heapMemOp = false;
407#endif
Bill Buzbeec6f10662010-02-09 11:16:15 -0800408 dvmCompilerFreeTemp(cUnit, regPtr);
Bill Buzbee1465db52009-09-23 17:17:35 -0700409 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700410 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800411 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
jeffhao9e45c0b2010-02-03 10:24:05 -0800412#if defined(WITH_SELF_VERIFICATION)
413 cUnit->heapMemOp = true;
414#endif
Bill Buzbee1465db52009-09-23 17:17:35 -0700415 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
416 scale, size);
jeffhao9e45c0b2010-02-03 10:24:05 -0800417#if defined(WITH_SELF_VERIFICATION)
418 cUnit->heapMemOp = false;
419#endif
Bill Buzbeec6f10662010-02-09 11:16:15 -0800420 dvmCompilerFreeTemp(cUnit, regPtr);
Bill Buzbee1465db52009-09-23 17:17:35 -0700421 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700422 }
423}
424
Ben Chengba4fc8b2009-06-01 13:00:29 -0700425/*
426 * Generate array store
427 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700428 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700429static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Bill Buzbee1465db52009-09-23 17:17:35 -0700430 RegLocation rlArray, RegLocation rlIndex,
431 RegLocation rlSrc, int scale)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700432{
433 int lenOffset = offsetof(ArrayObject, length);
434 int dataOffset = offsetof(ArrayObject, contents);
435
Bill Buzbee1465db52009-09-23 17:17:35 -0700436 int regPtr;
437 rlArray = loadValue(cUnit, rlArray, kCoreReg);
438 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
Ben Chenge9695e52009-06-16 16:11:47 -0700439
Bill Buzbeec6f10662010-02-09 11:16:15 -0800440 if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) {
441 dvmCompilerClobber(cUnit, rlArray.lowReg);
Bill Buzbee1465db52009-09-23 17:17:35 -0700442 regPtr = rlArray.lowReg;
443 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800444 regPtr = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700445 genRegCopy(cUnit, regPtr, rlArray.lowReg);
446 }
Ben Chenge9695e52009-06-16 16:11:47 -0700447
Ben Cheng1efc9c52009-06-08 18:25:27 -0700448 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -0700449 ArmLIR * pcrLabel = NULL;
450
451 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700452 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
453 mir->offset, NULL);
Ben Cheng4238ec22009-08-24 16:32:22 -0700454 }
455
456 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800457 int regLen = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700458 //NOTE: max live temps(4) here.
Ben Cheng4238ec22009-08-24 16:32:22 -0700459 /* Get len */
Bill Buzbee1465db52009-09-23 17:17:35 -0700460 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
461 /* regPtr -> array data */
462 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
463 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
464 pcrLabel);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800465 dvmCompilerFreeTemp(cUnit, regLen);
Ben Cheng4238ec22009-08-24 16:32:22 -0700466 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700467 /* regPtr -> array data */
468 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -0700469 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700470 /* at this point, regPtr points to array, 2 live temps */
Bill Buzbee1465db52009-09-23 17:17:35 -0700471 if ((size == kLong) || (size == kDouble)) {
472 //TODO: need specific wide routine that can handle fp regs
473 if (scale) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800474 int rNewIndex = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700475 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
476 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800477 dvmCompilerFreeTemp(cUnit, rNewIndex);
Bill Buzbee1465db52009-09-23 17:17:35 -0700478 } else {
479 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
480 }
481 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
jeffhao9e45c0b2010-02-03 10:24:05 -0800482#if defined(WITH_SELF_VERIFICATION)
483 cUnit->heapMemOp = true;
484#endif
Bill Buzbee1465db52009-09-23 17:17:35 -0700485 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
jeffhao9e45c0b2010-02-03 10:24:05 -0800486#if defined(WITH_SELF_VERIFICATION)
487 cUnit->heapMemOp = false;
488#endif
Bill Buzbeec6f10662010-02-09 11:16:15 -0800489 dvmCompilerFreeTemp(cUnit, regPtr);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700490 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700491 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
jeffhao9e45c0b2010-02-03 10:24:05 -0800492#if defined(WITH_SELF_VERIFICATION)
493 cUnit->heapMemOp = true;
494#endif
Bill Buzbee1465db52009-09-23 17:17:35 -0700495 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
496 scale, size);
jeffhao9e45c0b2010-02-03 10:24:05 -0800497#if defined(WITH_SELF_VERIFICATION)
498 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -0700499#endif
jeffhao9e45c0b2010-02-03 10:24:05 -0800500 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700501}
502
Ben Cheng5d90c202009-11-22 23:31:11 -0800503static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
504 RegLocation rlDest, RegLocation rlSrc1,
505 RegLocation rlShift)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700506{
Ben Chenge9695e52009-06-16 16:11:47 -0700507 /*
508 * Don't mess with the regsiters here as there is a particular calling
509 * convention to the out-of-line handler.
510 */
Bill Buzbee1465db52009-09-23 17:17:35 -0700511 RegLocation rlResult;
512
513 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
514 loadValueDirect(cUnit, rlShift, r2);
Ben Chenge9695e52009-06-16 16:11:47 -0700515 switch( mir->dalvikInsn.opCode) {
516 case OP_SHL_LONG:
517 case OP_SHL_LONG_2ADDR:
518 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
519 break;
520 case OP_SHR_LONG:
521 case OP_SHR_LONG_2ADDR:
522 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
523 break;
524 case OP_USHR_LONG:
525 case OP_USHR_LONG_2ADDR:
526 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
527 break;
528 default:
529 return true;
530 }
Bill Buzbeec6f10662010-02-09 11:16:15 -0800531 rlResult = dvmCompilerGetReturnWide(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700532 storeValueWide(cUnit, rlDest, rlResult);
Ben Chenge9695e52009-06-16 16:11:47 -0700533 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700534}
Ben Chenge9695e52009-06-16 16:11:47 -0700535
Ben Cheng5d90c202009-11-22 23:31:11 -0800536static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
537 RegLocation rlDest, RegLocation rlSrc1,
538 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700539{
Bill Buzbee1465db52009-09-23 17:17:35 -0700540 RegLocation rlResult;
541 OpKind firstOp = kOpBkpt;
542 OpKind secondOp = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700543 bool callOut = false;
544 void *callTgt;
545 int retReg = r0;
546 /* TODO - find proper .h file to declare these */
547 long long __aeabi_ldivmod(long long op1, long long op2);
548
549 switch (mir->dalvikInsn.opCode) {
550 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -0700551 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800552 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700553 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
554 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
555 storeValueWide(cUnit, rlDest, rlResult);
556 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700557 break;
558 case OP_ADD_LONG:
559 case OP_ADD_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700560 firstOp = kOpAdd;
561 secondOp = kOpAdc;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700562 break;
563 case OP_SUB_LONG:
564 case OP_SUB_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700565 firstOp = kOpSub;
566 secondOp = kOpSbc;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700567 break;
568 case OP_MUL_LONG:
569 case OP_MUL_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700570 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700571 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700572 case OP_DIV_LONG:
573 case OP_DIV_LONG_2ADDR:
574 callOut = true;
575 retReg = r0;
576 callTgt = (void*)__aeabi_ldivmod;
577 break;
578 /* NOTE - result is in r2/r3 instead of r0/r1 */
579 case OP_REM_LONG:
580 case OP_REM_LONG_2ADDR:
581 callOut = true;
582 callTgt = (void*)__aeabi_ldivmod;
583 retReg = r2;
584 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700585 case OP_AND_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700586 case OP_AND_LONG:
587 firstOp = kOpAnd;
588 secondOp = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700589 break;
590 case OP_OR_LONG:
591 case OP_OR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700592 firstOp = kOpOr;
593 secondOp = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700594 break;
595 case OP_XOR_LONG:
596 case OP_XOR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700597 firstOp = kOpXor;
598 secondOp = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700599 break;
Ben Chenge9695e52009-06-16 16:11:47 -0700600 case OP_NEG_LONG: {
Bill Buzbee51ecf602010-01-14 14:27:52 -0800601 //TUNING: can improve this using Thumb2 code
Bill Buzbeec6f10662010-02-09 11:16:15 -0800602 int tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700603 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800604 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee51ecf602010-01-14 14:27:52 -0800605 loadConstantValue(cUnit, tReg, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700606 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
Bill Buzbee51ecf602010-01-14 14:27:52 -0800607 tReg, rlSrc2.lowReg);
608 opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg);
609 genRegCopy(cUnit, rlResult.highReg, tReg);
Bill Buzbee1465db52009-09-23 17:17:35 -0700610 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700611 return false;
Ben Chenge9695e52009-06-16 16:11:47 -0700612 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700613 default:
614 LOGE("Invalid long arith op");
615 dvmAbort();
616 }
617 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700618 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700619 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700620 // Adjust return regs in to handle case of rem returning r2/r3
Bill Buzbeec6f10662010-02-09 11:16:15 -0800621 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -0700622 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
623 loadConstant(cUnit, rlr, (int) callTgt);
624 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
625 opReg(cUnit, kOpBlx, rlr);
Elliott Hughes6a555132010-02-25 15:41:42 -0800626 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700627 if (retReg == r0)
Bill Buzbeec6f10662010-02-09 11:16:15 -0800628 rlResult = dvmCompilerGetReturnWide(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700629 else
Bill Buzbeec6f10662010-02-09 11:16:15 -0800630 rlResult = dvmCompilerGetReturnWideAlt(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700631 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700632 }
633 return false;
634}
635
Ben Cheng5d90c202009-11-22 23:31:11 -0800636static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
637 RegLocation rlDest, RegLocation rlSrc1,
638 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700639{
Bill Buzbee1465db52009-09-23 17:17:35 -0700640 OpKind op = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700641 bool callOut = false;
642 bool checkZero = false;
Bill Buzbee1465db52009-09-23 17:17:35 -0700643 bool unary = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700644 int retReg = r0;
645 void *callTgt;
Bill Buzbee1465db52009-09-23 17:17:35 -0700646 RegLocation rlResult;
Bill Buzbee0e605272009-12-01 14:28:05 -0800647 bool shiftOp = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700648
649 /* TODO - find proper .h file to declare these */
650 int __aeabi_idivmod(int op1, int op2);
651 int __aeabi_idiv(int op1, int op2);
652
653 switch (mir->dalvikInsn.opCode) {
654 case OP_NEG_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -0700655 op = kOpNeg;
656 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700657 break;
658 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -0700659 op = kOpMvn;
660 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700661 break;
662 case OP_ADD_INT:
663 case OP_ADD_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700664 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700665 break;
666 case OP_SUB_INT:
667 case OP_SUB_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700668 op = kOpSub;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700669 break;
670 case OP_MUL_INT:
671 case OP_MUL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700672 op = kOpMul;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700673 break;
674 case OP_DIV_INT:
675 case OP_DIV_INT_2ADDR:
676 callOut = true;
677 checkZero = true;
678 callTgt = __aeabi_idiv;
679 retReg = r0;
680 break;
681 /* NOTE: returns in r1 */
682 case OP_REM_INT:
683 case OP_REM_INT_2ADDR:
684 callOut = true;
685 checkZero = true;
686 callTgt = __aeabi_idivmod;
687 retReg = r1;
688 break;
689 case OP_AND_INT:
690 case OP_AND_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700691 op = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700692 break;
693 case OP_OR_INT:
694 case OP_OR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700695 op = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700696 break;
697 case OP_XOR_INT:
698 case OP_XOR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -0700699 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700700 break;
701 case OP_SHL_INT:
702 case OP_SHL_INT_2ADDR:
Bill Buzbee0e605272009-12-01 14:28:05 -0800703 shiftOp = true;
Bill Buzbee1465db52009-09-23 17:17:35 -0700704 op = kOpLsl;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700705 break;
706 case OP_SHR_INT:
707 case OP_SHR_INT_2ADDR:
Bill Buzbee0e605272009-12-01 14:28:05 -0800708 shiftOp = true;
Bill Buzbee1465db52009-09-23 17:17:35 -0700709 op = kOpAsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700710 break;
711 case OP_USHR_INT:
712 case OP_USHR_INT_2ADDR:
Bill Buzbee0e605272009-12-01 14:28:05 -0800713 shiftOp = true;
Bill Buzbee1465db52009-09-23 17:17:35 -0700714 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700715 break;
716 default:
717 LOGE("Invalid word arith op: 0x%x(%d)",
718 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
719 dvmAbort();
720 }
721 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700722 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
723 if (unary) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800724 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700725 opRegReg(cUnit, op, rlResult.lowReg,
726 rlSrc1.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -0700727 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700728 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Bill Buzbee0e605272009-12-01 14:28:05 -0800729 if (shiftOp) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800730 int tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee0e605272009-12-01 14:28:05 -0800731 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800732 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee0e605272009-12-01 14:28:05 -0800733 opRegRegReg(cUnit, op, rlResult.lowReg,
734 rlSrc1.lowReg, tReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800735 dvmCompilerFreeTemp(cUnit, tReg);
Bill Buzbee0e605272009-12-01 14:28:05 -0800736 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800737 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee0e605272009-12-01 14:28:05 -0800738 opRegRegReg(cUnit, op, rlResult.lowReg,
739 rlSrc1.lowReg, rlSrc2.lowReg);
740 }
Ben Chenge9695e52009-06-16 16:11:47 -0700741 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700742 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700743 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700744 RegLocation rlResult;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800745 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -0700746 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700747 loadConstant(cUnit, r2, (int) callTgt);
Bill Buzbee1465db52009-09-23 17:17:35 -0700748 loadValueDirectFixed(cUnit, rlSrc1, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700749 if (checkZero) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700750 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700751 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700752 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -0800753 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700754 if (retReg == r0)
Bill Buzbeec6f10662010-02-09 11:16:15 -0800755 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700756 else
Bill Buzbeec6f10662010-02-09 11:16:15 -0800757 rlResult = dvmCompilerGetReturnAlt(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700758 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700759 }
760 return false;
761}
762
Ben Cheng5d90c202009-11-22 23:31:11 -0800763static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700764{
765 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -0700766 RegLocation rlDest;
767 RegLocation rlSrc1;
768 RegLocation rlSrc2;
769 /* Deduce sizes of operands */
770 if (mir->ssaRep->numUses == 2) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800771 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
772 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -0700773 } else if (mir->ssaRep->numUses == 3) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800774 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
775 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
Bill Buzbee1465db52009-09-23 17:17:35 -0700776 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800777 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
778 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
Bill Buzbee1465db52009-09-23 17:17:35 -0700779 assert(mir->ssaRep->numUses == 4);
780 }
781 if (mir->ssaRep->numDefs == 1) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800782 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -0700783 } else {
784 assert(mir->ssaRep->numDefs == 2);
Bill Buzbeec6f10662010-02-09 11:16:15 -0800785 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -0700786 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700787
788 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800789 return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700790 }
791 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800792 return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700793 }
794 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800795 return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700796 }
797 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800798 return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700799 }
800 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800801 return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700802 }
803 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800804 return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700805 }
806 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800807 return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700808 }
809 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800810 return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700811 }
812 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800813 return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700814 }
815 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Ben Cheng5d90c202009-11-22 23:31:11 -0800816 return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700817 }
818 return true;
819}
820
Bill Buzbee1465db52009-09-23 17:17:35 -0700821/* Generate conditional branch instructions */
822static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
823 ArmConditionCode cond,
824 ArmLIR *target)
825{
826 ArmLIR *branch = opCondBranch(cUnit, cond);
827 branch->generic.target = (LIR *) target;
828 return branch;
829}
830
831/* Generate unconditional branch instructions */
832static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
833{
834 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
835 branch->generic.target = (LIR *) target;
836 return branch;
837}
838
Bill Buzbee1465db52009-09-23 17:17:35 -0700839/* Perform the actual operation for OP_RETURN_* */
840static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
841{
842 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
843#if defined(INVOKE_STATS)
844 gDvmJit.returnOp++;
845#endif
846 int dPC = (int) (cUnit->method->insns + mir->offset);
847 /* Insert branch, but defer setting of target */
848 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
849 /* Set up the place holder to reconstruct this Dalvik PC */
850 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
851 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
852 pcrLabel->operands[0] = dPC;
853 pcrLabel->operands[1] = mir->offset;
854 /* Insert the place holder to the growable list */
855 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
856 /* Branch to the PC reconstruction code */
857 branch->generic.target = (LIR *) pcrLabel;
858}
859
Ben Chengba4fc8b2009-06-01 13:00:29 -0700860static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
861 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700862 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700863{
864 unsigned int i;
865 unsigned int regMask = 0;
Bill Buzbee1465db52009-09-23 17:17:35 -0700866 RegLocation rlArg;
867 int numDone = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700868
Bill Buzbee1465db52009-09-23 17:17:35 -0700869 /*
870 * Load arguments to r0..r4. Note that these registers may contain
871 * live values, so we clobber them immediately after loading to prevent
872 * them from being used as sources for subsequent loads.
873 */
Bill Buzbeec6f10662010-02-09 11:16:15 -0800874 dvmCompilerLockAllTemps(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700875 for (i = 0; i < dInsn->vA; i++) {
876 regMask |= 1 << i;
Bill Buzbeec6f10662010-02-09 11:16:15 -0800877 rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++);
Bill Buzbee1465db52009-09-23 17:17:35 -0700878 loadValueDirectFixed(cUnit, rlArg, i);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700879 }
880 if (regMask) {
881 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee1465db52009-09-23 17:17:35 -0700882 opRegRegImm(cUnit, kOpSub, r7, rFP,
883 sizeof(StackSaveArea) + (dInsn->vA << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700884 /* generate null check */
885 if (pcrLabel) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800886 *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
Bill Buzbee1465db52009-09-23 17:17:35 -0700887 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700888 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700889 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700890 }
891}
892
893static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
894 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700895 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700896{
897 int srcOffset = dInsn->vC << 2;
898 int numArgs = dInsn->vA;
899 int regMask;
Bill Buzbee1465db52009-09-23 17:17:35 -0700900
901 /*
902 * Note: here, all promoted registers will have been flushed
903 * back to the Dalvik base locations, so register usage restrictins
904 * are lifted. All parms loaded from original Dalvik register
905 * region - even though some might conceivably have valid copies
906 * cached in a preserved register.
907 */
Bill Buzbeec6f10662010-02-09 11:16:15 -0800908 dvmCompilerLockAllTemps(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700909
Ben Chengba4fc8b2009-06-01 13:00:29 -0700910 /*
911 * r4PC : &rFP[vC]
912 * r7: &newFP[0]
913 */
Bill Buzbee1465db52009-09-23 17:17:35 -0700914 opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700915 /* load [r0 .. min(numArgs,4)] */
916 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Ben Chengd7d426a2009-09-22 11:23:36 -0700917 /*
918 * Protect the loadMultiple instruction from being reordered with other
919 * Dalvik stack accesses.
920 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700921 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700922
Bill Buzbee1465db52009-09-23 17:17:35 -0700923 opRegRegImm(cUnit, kOpSub, r7, rFP,
924 sizeof(StackSaveArea) + (numArgs << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700925 /* generate null check */
926 if (pcrLabel) {
Bill Buzbeec6f10662010-02-09 11:16:15 -0800927 *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r0,
Bill Buzbee1465db52009-09-23 17:17:35 -0700928 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700929 }
930
931 /*
932 * Handle remaining 4n arguments:
933 * store previously loaded 4 values and load the next 4 values
934 */
935 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700936 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700937 /*
938 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -0700939 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -0700940 */
Bill Buzbee1465db52009-09-23 17:17:35 -0700941 opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700942 /* No need to generate the loop structure if numArgs <= 11 */
943 if (numArgs > 11) {
944 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee1465db52009-09-23 17:17:35 -0700945 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -0700946 loopLabel->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700947 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700948 storeMultiple(cUnit, r7, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -0700949 /*
950 * Protect the loadMultiple instruction from being reordered with other
951 * Dalvik stack accesses.
952 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700953 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700954 /* No need to generate the loop structure if numArgs <= 11 */
955 if (numArgs > 11) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700956 opRegImm(cUnit, kOpSub, rFP, 4);
957 genConditionalBranch(cUnit, kArmCondNe, loopLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700958 }
959 }
960
961 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700962 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700963
964 /* Generate the loop epilogue - don't use r0 */
965 if ((numArgs > 4) && (numArgs % 4)) {
966 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Ben Chengd7d426a2009-09-22 11:23:36 -0700967 /*
968 * Protect the loadMultiple instruction from being reordered with other
969 * Dalvik stack accesses.
970 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700971 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700972 }
973 if (numArgs >= 8)
Bill Buzbee1465db52009-09-23 17:17:35 -0700974 opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700975
976 /* Save the modulo 4 arguments */
977 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700978 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700979 }
980}
981
Ben Cheng38329f52009-07-07 14:19:20 -0700982/*
983 * Generate code to setup the call stack then jump to the chaining cell if it
984 * is not a native method.
985 */
986static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700987 BasicBlock *bb, ArmLIR *labelList,
988 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -0700989 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700990{
Bill Buzbee1465db52009-09-23 17:17:35 -0700991 /*
992 * Note: all Dalvik register state should be flushed to
993 * memory by the point, so register usage restrictions no
994 * longer apply. All temp & preserved registers may be used.
995 */
Bill Buzbeec6f10662010-02-09 11:16:15 -0800996 dvmCompilerLockAllTemps(cUnit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700997 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700998
999 /* r1 = &retChainingCell */
Bill Buzbeec6f10662010-02-09 11:16:15 -08001000 dvmCompilerLockTemp(cUnit, r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001001 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001002 /* r4PC = dalvikCallsite */
1003 loadConstant(cUnit, r4PC,
1004 (int) (cUnit->method->insns + mir->offset));
1005 addrRetChain->generic.target = (LIR *) retChainingCell;
1006 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001007 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001008 * r1 = &ChainingCell
1009 * r4PC = callsiteDPC
1010 */
1011 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001012 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001013#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001014 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001015#endif
1016 } else {
1017 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1018#if defined(INVOKE_STATS)
1019 gDvmJit.invokeChain++;
1020#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001021 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001022 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1023 }
1024 /* Handle exceptions using the interpreter */
1025 genTrap(cUnit, mir->offset, pcrLabel);
1026}
1027
Ben Cheng38329f52009-07-07 14:19:20 -07001028/*
1029 * Generate code to check the validity of a predicted chain and take actions
1030 * based on the result.
1031 *
1032 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1033 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1034 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1035 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1036 * 0x426a99b2 : blx_2 see above --+
1037 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1038 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1039 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1040 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1041 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1042 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1043 * 0x426a99c0 : blx r7 --+
1044 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1045 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1046 * 0x426a99c6 : blx_2 see above --+
1047 */
1048static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1049 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001050 ArmLIR *retChainingCell,
1051 ArmLIR *predChainingCell,
1052 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001053{
Bill Buzbee1465db52009-09-23 17:17:35 -07001054 /*
1055 * Note: all Dalvik register state should be flushed to
1056 * memory by the point, so register usage restrictions no
1057 * longer apply. Lock temps to prevent them from being
1058 * allocated by utility routines.
1059 */
Bill Buzbeec6f10662010-02-09 11:16:15 -08001060 dvmCompilerLockAllTemps(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001061
Ben Cheng38329f52009-07-07 14:19:20 -07001062 /* "this" is already left in r0 by genProcessArgs* */
1063
1064 /* r4PC = dalvikCallsite */
1065 loadConstant(cUnit, r4PC,
1066 (int) (cUnit->method->insns + mir->offset));
1067
1068 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07001069 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001070 addrRetChain->generic.target = (LIR *) retChainingCell;
1071
1072 /* r2 = &predictedChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07001073 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001074 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1075
1076 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1077
1078 /* return through lr - jump to the chaining cell */
1079 genUnconditionalBranch(cUnit, predChainingCell);
1080
1081 /*
1082 * null-check on "this" may have been eliminated, but we still need a PC-
1083 * reconstruction label for stack overflow bailout.
1084 */
1085 if (pcrLabel == NULL) {
1086 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001087 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001088 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001089 pcrLabel->operands[0] = dPC;
1090 pcrLabel->operands[1] = mir->offset;
1091 /* Insert the place holder to the growable list */
1092 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1093 }
1094
1095 /* return through lr+2 - punt to the interpreter */
1096 genUnconditionalBranch(cUnit, pcrLabel);
1097
1098 /*
1099 * return through lr+4 - fully resolve the callee method.
1100 * r1 <- count
1101 * r2 <- &predictedChainCell
1102 * r3 <- this->class
1103 * r4 <- dPC
1104 * r7 <- this->class->vtable
1105 */
1106
1107 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001108 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001109
1110 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07001111 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001112
Bill Buzbee1465db52009-09-23 17:17:35 -07001113 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07001114
Bill Buzbee270c1d62009-08-13 16:58:07 -07001115 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1116 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001117
1118 /*
1119 * r0 = calleeMethod
1120 * r2 = &predictedChainingCell
1121 * r3 = class
1122 *
1123 * &returnChainingCell has been loaded into r1 but is not needed
1124 * when patching the chaining cell and will be clobbered upon
1125 * returning so it will be reconstructed again.
1126 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001127 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001128
1129 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07001130 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001131 addrRetChain->generic.target = (LIR *) retChainingCell;
1132
1133 bypassRechaining->generic.target = (LIR *) addrRetChain;
1134 /*
1135 * r0 = calleeMethod,
1136 * r1 = &ChainingCell,
1137 * r4PC = callsiteDPC,
1138 */
1139 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1140#if defined(INVOKE_STATS)
1141 gDvmJit.invokePredictedChain++;
1142#endif
1143 /* Handle exceptions using the interpreter */
1144 genTrap(cUnit, mir->offset, pcrLabel);
1145}
1146
1147/*
1148 * Up calling this function, "this" is stored in r0. The actual class will be
1149 * chased down off r0 and the predicted one will be retrieved through
1150 * predictedChainingCell then a comparison is performed to see whether the
1151 * previously established chaining is still valid.
1152 *
1153 * The return LIR is a branch based on the comparison result. The actual branch
1154 * target will be setup in the caller.
1155 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001156static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1157 ArmLIR *predChainingCell,
1158 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001159 MIR *mir)
1160{
Bill Buzbee1465db52009-09-23 17:17:35 -07001161 /*
1162 * Note: all Dalvik register state should be flushed to
1163 * memory by the point, so register usage restrictions no
1164 * longer apply. All temp & preserved registers may be used.
1165 */
Bill Buzbeec6f10662010-02-09 11:16:15 -08001166 dvmCompilerLockAllTemps(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001167
Ben Cheng38329f52009-07-07 14:19:20 -07001168 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001169 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001170
1171 /*
1172 * r2 now contains predicted class. The starting offset of the
1173 * cached value is 4 bytes into the chaining cell.
1174 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001175 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001176 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07001177 getPredictedClass->generic.target = (LIR *) predChainingCell;
1178
1179 /*
1180 * r0 now contains predicted method. The starting offset of the
1181 * cached value is 8 bytes into the chaining cell.
1182 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001183 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001184 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001185 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1186
1187 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001188 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001189 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001190 getRechainingRequestCount->generic.target =
1191 (LIR *) predChainingCell;
1192
1193 /* r4PC = dalvikCallsite */
1194 loadConstant(cUnit, r4PC,
1195 (int) (cUnit->method->insns + mir->offset));
1196
1197 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07001198 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07001199 addrRetChain->generic.target = (LIR *) retChainingCell;
1200
1201 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee1465db52009-09-23 17:17:35 -07001202 opRegReg(cUnit, kOpCmp, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001203
Bill Buzbee1465db52009-09-23 17:17:35 -07001204 return opCondBranch(cUnit, kArmCondEq);
Ben Cheng38329f52009-07-07 14:19:20 -07001205}
1206
Ben Chengba4fc8b2009-06-01 13:00:29 -07001207/* Geneate a branch to go back to the interpreter */
1208static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1209{
1210 /* r0 = dalvik pc */
Bill Buzbeec6f10662010-02-09 11:16:15 -08001211 dvmCompilerFlushAllRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001212 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001213 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1214 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1215 jitToInterpEntries.dvmJitToInterpPunt), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001216 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001217}
1218
1219/*
1220 * Attempt to single step one instruction using the interpreter and return
1221 * to the compiled code for the next Dalvik instruction
1222 */
1223static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1224{
1225 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1226 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1227 kInstrCanThrow;
Bill Buzbee1465db52009-09-23 17:17:35 -07001228
1229 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
Bill Buzbeec6f10662010-02-09 11:16:15 -08001230 dvmCompilerFlushAllRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001231
Ben Chengba4fc8b2009-06-01 13:00:29 -07001232 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1233 genPuntToInterp(cUnit, mir->offset);
1234 return;
1235 }
1236 int entryAddr = offsetof(InterpState,
1237 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001238 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001239 /* r0 = dalvik pc */
1240 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1241 /* r1 = dalvik pc of following instruction */
1242 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -07001243 opReg(cUnit, kOpBlx, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001244}
1245
Bill Buzbeec1d9ed42010-02-02 11:04:33 -08001246/*
1247 * To prevent a thread in a monitor wait from blocking the Jit from
1248 * resetting the code cache, heavyweight monitor lock will not
1249 * be allowed to return to an existing translation. Instead, we will
1250 * handle them by branching to a handler, which will in turn call the
1251 * runtime lock routine and then branch directly back to the
1252 * interpreter main loop. Given the high cost of the heavyweight
1253 * lock operation, this additional cost should be slight (especially when
1254 * considering that we expect the vast majority of lock operations to
1255 * use the fast-path thin lock bypass).
1256 */
Ben Cheng5d90c202009-11-22 23:31:11 -08001257static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001258{
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08001259 bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
Bill Buzbee1465db52009-09-23 17:17:35 -07001260 genExportPC(cUnit, mir);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001261 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
1262 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001263 loadValueDirectFixed(cUnit, rlSrc, r1);
1264 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
Bill Buzbeec1d9ed42010-02-02 11:04:33 -08001265 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08001266 if (isEnter) {
Bill Buzbeec1d9ed42010-02-02 11:04:33 -08001267 /* Get dPC of next insn */
1268 loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
1269 dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER)));
1270#if defined(WITH_DEADLOCK_PREDICTION)
1271 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER_DEBUG);
1272#else
1273 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
1274#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001275 } else {
1276 loadConstant(cUnit, r2, (int)dvmUnlockObject);
Bill Buzbeec1d9ed42010-02-02 11:04:33 -08001277 /* Do the call */
1278 opReg(cUnit, kOpBlx, r2);
Bill Buzbee6bbdd6b2010-02-16 14:40:01 -08001279 opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
1280 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
1281 loadConstant(cUnit, r0,
1282 (int) (cUnit->method->insns + mir->offset +
1283 dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
1284 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1285 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1286 target->defMask = ENCODE_ALL;
1287 branchOver->generic.target = (LIR *) target;
Elliott Hughes6a555132010-02-25 15:41:42 -08001288 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001289 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001290}
1291
Ben Chengba4fc8b2009-06-01 13:00:29 -07001292/*
1293 * The following are the first-level codegen routines that analyze the format
1294 * of each bytecode then either dispatch special purpose codegen routines
1295 * or produce corresponding Thumb instructions directly.
1296 */
1297
1298static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001299 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001300{
1301 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1302 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1303 return false;
1304}
1305
1306static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1307{
1308 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1309 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
Andy McFadden96516932009-10-28 17:39:02 -07001310 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EB))) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001311 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1312 return true;
1313 }
1314 switch (dalvikOpCode) {
1315 case OP_RETURN_VOID:
1316 genReturnCommon(cUnit,mir);
1317 break;
1318 case OP_UNUSED_73:
1319 case OP_UNUSED_79:
1320 case OP_UNUSED_7A:
1321 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1322 return true;
1323 case OP_NOP:
1324 break;
1325 default:
1326 return true;
1327 }
1328 return false;
1329}
1330
1331static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1332{
Bill Buzbee1465db52009-09-23 17:17:35 -07001333 RegLocation rlDest;
1334 RegLocation rlResult;
1335 if (mir->ssaRep->numDefs == 2) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001336 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001337 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001338 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001339 }
Ben Chenge9695e52009-06-16 16:11:47 -07001340
Ben Chengba4fc8b2009-06-01 13:00:29 -07001341 switch (mir->dalvikInsn.opCode) {
1342 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001343 case OP_CONST_4: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001344 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001345 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1346 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001347 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001348 }
1349 case OP_CONST_WIDE_32: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001350 //TUNING: single routine to load constant pair for support doubles
Bill Buzbee964a7b02010-01-28 12:54:19 -08001351 //TUNING: load 0/-1 separately to avoid load dependency
Bill Buzbeec6f10662010-02-09 11:16:15 -08001352 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001353 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1354 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1355 rlResult.lowReg, 31);
1356 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001357 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001358 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001359 default:
1360 return true;
1361 }
1362 return false;
1363}
1364
1365static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1366{
Bill Buzbee1465db52009-09-23 17:17:35 -07001367 RegLocation rlDest;
1368 RegLocation rlResult;
1369 if (mir->ssaRep->numDefs == 2) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001370 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001371 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001372 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001373 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08001374 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Ben Chenge9695e52009-06-16 16:11:47 -07001375
Ben Chengba4fc8b2009-06-01 13:00:29 -07001376 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001377 case OP_CONST_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001378 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
1379 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001380 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001381 }
1382 case OP_CONST_WIDE_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001383 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1384 0, mir->dalvikInsn.vB << 16);
1385 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001386 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001387 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001388 default:
1389 return true;
1390 }
1391 return false;
1392}
1393
1394static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1395{
1396 /* For OP_THROW_VERIFICATION_ERROR */
1397 genInterpSingleStep(cUnit, mir);
1398 return false;
1399}
1400
1401static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1402{
Bill Buzbee1465db52009-09-23 17:17:35 -07001403 RegLocation rlResult;
1404 RegLocation rlDest;
1405 RegLocation rlSrc;
Ben Chenge9695e52009-06-16 16:11:47 -07001406
Ben Chengba4fc8b2009-06-01 13:00:29 -07001407 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001408 case OP_CONST_STRING_JUMBO:
1409 case OP_CONST_STRING: {
1410 void *strPtr = (void*)
1411 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1412 assert(strPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001413 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1414 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001415 loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
1416 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001417 break;
1418 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001419 case OP_CONST_CLASS: {
1420 void *classPtr = (void*)
1421 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1422 assert(classPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001423 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1424 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001425 loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
1426 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001427 break;
1428 }
1429 case OP_SGET_OBJECT:
1430 case OP_SGET_BOOLEAN:
1431 case OP_SGET_CHAR:
1432 case OP_SGET_BYTE:
1433 case OP_SGET_SHORT:
1434 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001435 int valOffset = offsetof(StaticField, value);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001436 int tReg = dvmCompilerAllocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001437 void *fieldPtr = (void*)
1438 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1439 assert(fieldPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001440 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1441 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001442 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -08001443#if defined(WITH_SELF_VERIFICATION)
1444 cUnit->heapMemOp = true;
1445#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001446 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
jeffhao9e45c0b2010-02-03 10:24:05 -08001447#if defined(WITH_SELF_VERIFICATION)
1448 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -07001449#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001450 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001451 break;
1452 }
1453 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001454 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001455 void *fieldPtr = (void*)
1456 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001457 int tReg = dvmCompilerAllocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001458 assert(fieldPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001459 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1460 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001461 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -08001462#if defined(WITH_SELF_VERIFICATION)
1463 cUnit->heapMemOp = true;
1464#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001465 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
jeffhao9e45c0b2010-02-03 10:24:05 -08001466#if defined(WITH_SELF_VERIFICATION)
1467 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -07001468#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001469 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001470 break;
1471 }
1472 case OP_SPUT_OBJECT:
1473 case OP_SPUT_BOOLEAN:
1474 case OP_SPUT_CHAR:
1475 case OP_SPUT_BYTE:
1476 case OP_SPUT_SHORT:
1477 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001478 int valOffset = offsetof(StaticField, value);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001479 int tReg = dvmCompilerAllocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001480 void *fieldPtr = (void*)
1481 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001482
Ben Chengba4fc8b2009-06-01 13:00:29 -07001483 assert(fieldPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001484 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001485 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1486 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -08001487#if defined(WITH_SELF_VERIFICATION)
1488 cUnit->heapMemOp = true;
1489#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001490 storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
jeffhao9e45c0b2010-02-03 10:24:05 -08001491#if defined(WITH_SELF_VERIFICATION)
1492 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -07001493#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001494 break;
1495 }
1496 case OP_SPUT_WIDE: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001497 int tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001498 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001499 void *fieldPtr = (void*)
1500 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001501
Ben Chengba4fc8b2009-06-01 13:00:29 -07001502 assert(fieldPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001503 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001504 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1505 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -08001506#if defined(WITH_SELF_VERIFICATION)
1507 cUnit->heapMemOp = true;
1508#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001509 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
jeffhao9e45c0b2010-02-03 10:24:05 -08001510#if defined(WITH_SELF_VERIFICATION)
1511 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -07001512#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001513 break;
1514 }
1515 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001516 /*
1517 * Obey the calling convention and don't mess with the register
1518 * usage.
1519 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001520 ClassObject *classPtr = (void*)
1521 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1522 assert(classPtr != NULL);
1523 assert(classPtr->status & CLASS_INITIALIZED);
Ben Cheng79d173c2009-09-29 16:12:51 -07001524 /*
1525 * If it is going to throw, it should not make to the trace to begin
Bill Buzbee1465db52009-09-23 17:17:35 -07001526 * with. However, Alloc might throw, so we need to genExportPC()
Ben Cheng79d173c2009-09-29 16:12:51 -07001527 */
1528 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001529 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001530 genExportPC(cUnit, mir);
1531 loadConstant(cUnit, r2, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07001532 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001533 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07001534 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -08001535 dvmCompilerClobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07001536 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07001537 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
1538 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07001539 /*
1540 * OOM exception needs to be thrown here and cannot re-execute
1541 */
1542 loadConstant(cUnit, r0,
1543 (int) (cUnit->method->insns + mir->offset));
1544 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1545 /* noreturn */
1546
Bill Buzbee1465db52009-09-23 17:17:35 -07001547 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07001548 target->defMask = ENCODE_ALL;
1549 branchOver->generic.target = (LIR *) target;
Bill Buzbeec6f10662010-02-09 11:16:15 -08001550 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1551 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001552 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001553 break;
1554 }
1555 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07001556 /*
1557 * Obey the calling convention and don't mess with the register
1558 * usage.
1559 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001560 ClassObject *classPtr =
1561 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
Bill Buzbee4df41a52009-11-12 17:07:16 -08001562 /*
1563 * Note: It is possible that classPtr is NULL at this point,
1564 * even though this instruction has been successfully interpreted.
1565 * If the previous interpretation had a null source, the
1566 * interpreter would not have bothered to resolve the clazz.
1567 * Bail out to the interpreter in this case, and log it
1568 * so that we can tell if it happens frequently.
1569 */
1570 if (classPtr == NULL) {
1571 LOGD("null clazz in OP_CHECK_CAST, single-stepping");
1572 genInterpSingleStep(cUnit, mir);
1573 return false;
1574 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08001575 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001576 loadConstant(cUnit, r1, (int) classPtr );
Bill Buzbeec6f10662010-02-09 11:16:15 -08001577 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001578 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1579 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); /* Null? */
1580 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
1581 /*
1582 * rlSrc.lowReg now contains object->clazz. Note that
1583 * it could have been allocated r0, but we're okay so long
1584 * as we don't do anything desctructive until r0 is loaded
1585 * with clazz.
1586 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001587 /* r0 now contains object->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07001588 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
1589 loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
1590 opRegReg(cUnit, kOpCmp, r0, r1);
1591 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
1592 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -08001593 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001594 /*
1595 * If null, check cast failed - punt to the interpreter. Because
1596 * interpreter will be the one throwing, we don't need to
1597 * genExportPC() here.
1598 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001599 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001600 /* check cast passed - branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07001601 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07001602 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001603 branch1->generic.target = (LIR *)target;
1604 branch2->generic.target = (LIR *)target;
1605 break;
1606 }
1607 default:
1608 return true;
1609 }
1610 return false;
1611}
1612
1613static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1614{
1615 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001616 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001617 switch (dalvikOpCode) {
1618 case OP_MOVE_EXCEPTION: {
1619 int offset = offsetof(InterpState, self);
1620 int exOffset = offsetof(Thread, exception);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001621 int selfReg = dvmCompilerAllocTemp(cUnit);
1622 int resetReg = dvmCompilerAllocTemp(cUnit);
1623 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1624 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001625 loadWordDisp(cUnit, rGLUE, offset, selfReg);
Bill Buzbeef9f33282009-11-22 12:45:30 -08001626 loadConstant(cUnit, resetReg, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001627 loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
Bill Buzbeef9f33282009-11-22 12:45:30 -08001628 storeWordDisp(cUnit, selfReg, exOffset, resetReg);
Bill Buzbee1465db52009-09-23 17:17:35 -07001629 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001630 break;
1631 }
1632 case OP_MOVE_RESULT:
1633 case OP_MOVE_RESULT_OBJECT: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001634 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001635 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
1636 rlSrc.fp = rlDest.fp;
1637 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001638 break;
1639 }
1640 case OP_MOVE_RESULT_WIDE: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001641 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001642 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
1643 rlSrc.fp = rlDest.fp;
1644 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001645 break;
1646 }
1647 case OP_RETURN_WIDE: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001648 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001649 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
1650 rlDest.fp = rlSrc.fp;
1651 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001652 genReturnCommon(cUnit,mir);
1653 break;
1654 }
1655 case OP_RETURN:
1656 case OP_RETURN_OBJECT: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001657 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001658 RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
1659 rlDest.fp = rlSrc.fp;
1660 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001661 genReturnCommon(cUnit,mir);
1662 break;
1663 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001664 case OP_MONITOR_EXIT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001665 case OP_MONITOR_ENTER:
Bill Buzbeed0937ef2009-12-22 16:15:39 -08001666#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
Ben Cheng5d90c202009-11-22 23:31:11 -08001667 genMonitorPortable(cUnit, mir);
Bill Buzbee1465db52009-09-23 17:17:35 -07001668#else
Ben Cheng5d90c202009-11-22 23:31:11 -08001669 genMonitor(cUnit, mir);
Bill Buzbee1465db52009-09-23 17:17:35 -07001670#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001671 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001672 case OP_THROW: {
1673 genInterpSingleStep(cUnit, mir);
1674 break;
1675 }
1676 default:
1677 return true;
1678 }
1679 return false;
1680}
1681
Bill Buzbeed45ba372009-06-15 17:00:57 -07001682static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1683{
1684 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001685 RegLocation rlDest;
1686 RegLocation rlSrc;
1687 RegLocation rlResult;
Bill Buzbeed45ba372009-06-15 17:00:57 -07001688
Ben Chengba4fc8b2009-06-01 13:00:29 -07001689 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Ben Cheng5d90c202009-11-22 23:31:11 -08001690 return genArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07001691 }
1692
Bill Buzbee1465db52009-09-23 17:17:35 -07001693 if (mir->ssaRep->numUses == 2)
Bill Buzbeec6f10662010-02-09 11:16:15 -08001694 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001695 else
Bill Buzbeec6f10662010-02-09 11:16:15 -08001696 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001697 if (mir->ssaRep->numDefs == 2)
Bill Buzbeec6f10662010-02-09 11:16:15 -08001698 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001699 else
Bill Buzbeec6f10662010-02-09 11:16:15 -08001700 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Ben Chenge9695e52009-06-16 16:11:47 -07001701
Ben Chengba4fc8b2009-06-01 13:00:29 -07001702 switch (opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001703 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001704 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001705 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001706 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001707 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001708 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001709 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001710 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001711 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001712 case OP_LONG_TO_DOUBLE:
Ben Cheng5d90c202009-11-22 23:31:11 -08001713 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001714 case OP_NEG_INT:
1715 case OP_NOT_INT:
Ben Cheng5d90c202009-11-22 23:31:11 -08001716 return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001717 case OP_NEG_LONG:
1718 case OP_NOT_LONG:
Ben Cheng5d90c202009-11-22 23:31:11 -08001719 return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001720 case OP_NEG_FLOAT:
Ben Cheng5d90c202009-11-22 23:31:11 -08001721 return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001722 case OP_NEG_DOUBLE:
Ben Cheng5d90c202009-11-22 23:31:11 -08001723 return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
Bill Buzbee1465db52009-09-23 17:17:35 -07001724 case OP_MOVE_WIDE:
1725 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001726 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001727 case OP_INT_TO_LONG:
Bill Buzbeec6f10662010-02-09 11:16:15 -08001728 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
1729 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee964a7b02010-01-28 12:54:19 -08001730 //TUNING: shouldn't loadValueDirect already check for phys reg?
Bill Buzbee1465db52009-09-23 17:17:35 -07001731 if (rlSrc.location == kLocPhysReg) {
1732 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
1733 } else {
1734 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
1735 }
1736 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1737 rlResult.lowReg, 31);
1738 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001739 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001740 case OP_LONG_TO_INT:
Bill Buzbeec6f10662010-02-09 11:16:15 -08001741 rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
1742 rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
Bill Buzbee1465db52009-09-23 17:17:35 -07001743 // Intentional fallthrough
Ben Chengba4fc8b2009-06-01 13:00:29 -07001744 case OP_MOVE:
1745 case OP_MOVE_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001746 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001747 break;
1748 case OP_INT_TO_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07001749 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001750 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001751 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
1752 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001753 break;
1754 case OP_INT_TO_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001755 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001756 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001757 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
1758 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001759 break;
1760 case OP_INT_TO_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001761 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001762 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001763 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
1764 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001765 break;
1766 case OP_ARRAY_LENGTH: {
1767 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07001768 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1769 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
1770 mir->offset, NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001771 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001772 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
1773 rlResult.lowReg);
1774 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001775 break;
1776 }
1777 default:
1778 return true;
1779 }
1780 return false;
1781}
1782
1783static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1784{
1785 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001786 RegLocation rlDest;
1787 RegLocation rlResult;
1788 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001789 if (dalvikOpCode == OP_CONST_WIDE_16) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001790 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1791 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001792 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
Bill Buzbee964a7b02010-01-28 12:54:19 -08001793 //TUNING: do high separately to avoid load dependency
Bill Buzbee1465db52009-09-23 17:17:35 -07001794 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1795 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001796 } else if (dalvikOpCode == OP_CONST_16) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001797 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1798 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001799 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
1800 storeValue(cUnit, rlDest, rlResult);
1801 } else
Ben Chengba4fc8b2009-06-01 13:00:29 -07001802 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001803 return false;
1804}
1805
1806/* Compare agaist zero */
1807static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001808 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001809{
1810 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001811 ArmConditionCode cond;
Bill Buzbeec6f10662010-02-09 11:16:15 -08001812 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001813 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1814 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001815
Bill Buzbee270c1d62009-08-13 16:58:07 -07001816//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07001817 switch (dalvikOpCode) {
1818 case OP_IF_EQZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001819 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001820 break;
1821 case OP_IF_NEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001822 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001823 break;
1824 case OP_IF_LTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001825 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001826 break;
1827 case OP_IF_GEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001828 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001829 break;
1830 case OP_IF_GTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001831 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001832 break;
1833 case OP_IF_LEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001834 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001835 break;
1836 default:
1837 cond = 0;
1838 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
1839 dvmAbort();
1840 }
1841 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1842 /* This mostly likely will be optimized away in a later phase */
1843 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1844 return false;
1845}
1846
Elliott Hughesb4c05972010-02-24 16:36:18 -08001847static bool isPowerOfTwo(int x)
1848{
1849 return (x & (x - 1)) == 0;
1850}
1851
1852// Returns true if no more than two bits are set in 'x'.
1853static bool isPopCountLE2(unsigned int x)
1854{
1855 x &= x - 1;
1856 return (x & (x - 1)) == 0;
1857}
1858
1859// Returns the index of the lowest set bit in 'x'.
1860static int lowestSetBit(unsigned int x) {
1861 int bit_posn = 0;
1862 while ((x & 0xf) == 0) {
1863 bit_posn += 4;
1864 x >>= 4;
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001865 }
Elliott Hughesb4c05972010-02-24 16:36:18 -08001866 while ((x & 1) == 0) {
1867 bit_posn++;
1868 x >>= 1;
1869 }
1870 return bit_posn;
1871}
1872
1873// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1874// and store the result in 'rlDest'.
1875static bool handleEasyMultiply(CompilationUnit *cUnit,
1876 RegLocation rlSrc, RegLocation rlDest, int lit)
1877{
1878 // Can we simplify this multiplication?
1879 bool powerOfTwo = false;
1880 bool popCountLE2 = false;
1881 bool powerOfTwoMinusOne = false;
1882 if (lit < 2) {
1883 // Avoid special cases.
1884 return false;
1885 } else if (isPowerOfTwo(lit)) {
1886 powerOfTwo = true;
1887 } else if (isPopCountLE2(lit)) {
1888 popCountLE2 = true;
1889 } else if (isPowerOfTwo(lit + 1)) {
1890 powerOfTwoMinusOne = true;
1891 } else {
1892 return false;
1893 }
1894 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1895 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1896 if (powerOfTwo) {
1897 // Shift.
1898 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1899 lowestSetBit(lit));
1900 } else if (popCountLE2) {
1901 // Shift and add and shift.
1902 int firstBit = lowestSetBit(lit);
1903 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1904 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1905 firstBit, secondBit);
1906 } else {
1907 // Reverse subtract: (src << (shift + 1)) - src.
1908 assert(powerOfTwoMinusOne);
1909 // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1910 int tReg = dvmCompilerAllocTemp(cUnit);
1911 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1912 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1913 }
1914 storeValue(cUnit, rlDest, rlResult);
1915 return true;
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001916}
1917
Ben Chengba4fc8b2009-06-01 13:00:29 -07001918static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1919{
1920 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbeec6f10662010-02-09 11:16:15 -08001921 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1922 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001923 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001924 int lit = mir->dalvikInsn.vC;
Ben Cheng4f489172009-09-27 17:08:35 -07001925 OpKind op = 0; /* Make gcc happy */
Bill Buzbee1465db52009-09-23 17:17:35 -07001926 int shiftOp = false;
1927 bool isDiv = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001928
Ben Chengba4fc8b2009-06-01 13:00:29 -07001929 int __aeabi_idivmod(int op1, int op2);
1930 int __aeabi_idiv(int op1, int op2);
1931
1932 switch (dalvikOpCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001933 case OP_RSUB_INT_LIT8:
1934 case OP_RSUB_INT: {
1935 int tReg;
1936 //TUNING: add support for use of Arm rsub op
1937 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001938 tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001939 loadConstant(cUnit, tReg, lit);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001940 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001941 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1942 tReg, rlSrc.lowReg);
1943 storeValue(cUnit, rlDest, rlResult);
1944 return false;
1945 break;
1946 }
1947
Ben Chengba4fc8b2009-06-01 13:00:29 -07001948 case OP_ADD_INT_LIT8:
1949 case OP_ADD_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07001950 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001951 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001952 case OP_MUL_INT_LIT8:
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001953 case OP_MUL_INT_LIT16: {
Elliott Hughesb4c05972010-02-24 16:36:18 -08001954 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1955 return false;
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001956 }
Elliott Hughesb4c05972010-02-24 16:36:18 -08001957 op = kOpMul;
Bill Buzbee1465db52009-09-23 17:17:35 -07001958 break;
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001959 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001960 case OP_AND_INT_LIT8:
1961 case OP_AND_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07001962 op = kOpAnd;
1963 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001964 case OP_OR_INT_LIT8:
1965 case OP_OR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07001966 op = kOpOr;
1967 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001968 case OP_XOR_INT_LIT8:
1969 case OP_XOR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07001970 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001971 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001972 case OP_SHL_INT_LIT8:
Bill Buzbee0e605272009-12-01 14:28:05 -08001973 lit &= 31;
Bill Buzbee1465db52009-09-23 17:17:35 -07001974 shiftOp = true;
1975 op = kOpLsl;
1976 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001977 case OP_SHR_INT_LIT8:
Bill Buzbee0e605272009-12-01 14:28:05 -08001978 lit &= 31;
Bill Buzbee1465db52009-09-23 17:17:35 -07001979 shiftOp = true;
1980 op = kOpAsr;
1981 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001982 case OP_USHR_INT_LIT8:
Bill Buzbee0e605272009-12-01 14:28:05 -08001983 lit &= 31;
Bill Buzbee1465db52009-09-23 17:17:35 -07001984 shiftOp = true;
1985 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001986 break;
1987
1988 case OP_DIV_INT_LIT8:
1989 case OP_DIV_INT_LIT16:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001990 case OP_REM_INT_LIT8:
1991 case OP_REM_INT_LIT16:
1992 if (lit == 0) {
1993 /* Let the interpreter deal with div by 0 */
1994 genInterpSingleStep(cUnit, mir);
1995 return false;
1996 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08001997 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001998 loadValueDirectFixed(cUnit, rlSrc, r0);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001999 dvmCompilerClobber(cUnit, r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002000 if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2001 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2002 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2003 isDiv = true;
2004 } else {
2005 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2006 isDiv = false;
2007 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002008 loadConstant(cUnit, r1, lit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002009 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -08002010 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002011 if (isDiv)
Bill Buzbeec6f10662010-02-09 11:16:15 -08002012 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002013 else
Bill Buzbeec6f10662010-02-09 11:16:15 -08002014 rlResult = dvmCompilerGetReturnAlt(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002015 storeValue(cUnit, rlDest, rlResult);
2016 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002017 break;
2018 default:
2019 return true;
2020 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002021 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002022 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07002023 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2024 if (shiftOp && (lit == 0)) {
2025 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2026 } else {
2027 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2028 }
2029 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002030 return false;
2031}
2032
2033static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2034{
2035 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2036 int fieldOffset;
2037
2038 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2039 InstField *pInstField = (InstField *)
2040 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002041
2042 assert(pInstField != NULL);
2043 fieldOffset = pInstField->byteOffset;
2044 } else {
Ben Chenga0e7b602009-10-13 23:09:01 -07002045 /* Deliberately break the code while make the compiler happy */
2046 fieldOffset = -1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002047 }
2048 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002049 case OP_NEW_ARRAY: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002050 // Generates a call - use explicit registers
Bill Buzbeec6f10662010-02-09 11:16:15 -08002051 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2052 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002053 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002054 void *classPtr = (void*)
2055 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2056 assert(classPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002057 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002058 genExportPC(cUnit, mir);
2059 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002060 loadConstant(cUnit, r0, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07002061 loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
Ben Cheng4f489172009-09-27 17:08:35 -07002062 /*
2063 * "len < 0": bail to the interpreter to re-execute the
2064 * instruction
2065 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002066 ArmLIR *pcrLabel =
Bill Buzbee1465db52009-09-23 17:17:35 -07002067 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002068 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07002069 opReg(cUnit, kOpBlx, r3);
Elliott Hughes6a555132010-02-25 15:41:42 -08002070 dvmCompilerClobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07002071 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07002072 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2073 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07002074 /*
2075 * OOM exception needs to be thrown here and cannot re-execute
2076 */
2077 loadConstant(cUnit, r0,
2078 (int) (cUnit->method->insns + mir->offset));
2079 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2080 /* noreturn */
2081
Bill Buzbee1465db52009-09-23 17:17:35 -07002082 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07002083 target->defMask = ENCODE_ALL;
2084 branchOver->generic.target = (LIR *) target;
Bill Buzbeec6f10662010-02-09 11:16:15 -08002085 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002086 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002087 break;
2088 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002089 case OP_INSTANCE_OF: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002090 // May generate a call - use explicit registers
Bill Buzbeec6f10662010-02-09 11:16:15 -08002091 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2092 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002093 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002094 ClassObject *classPtr =
2095 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
Bill Buzbee480e6782010-01-27 15:43:08 -08002096 /*
2097 * Note: It is possible that classPtr is NULL at this point,
2098 * even though this instruction has been successfully interpreted.
2099 * If the previous interpretation had a null source, the
2100 * interpreter would not have bothered to resolve the clazz.
2101 * Bail out to the interpreter in this case, and log it
2102 * so that we can tell if it happens frequently.
2103 */
2104 if (classPtr == NULL) {
2105 LOGD("null clazz in OP_INSTANCE_OF, single-stepping");
2106 genInterpSingleStep(cUnit, mir);
2107 break;
2108 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08002109 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002110 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002111 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002112//TUNING: compare to 0 primative to allow use of CB[N]Z
Bill Buzbee1465db52009-09-23 17:17:35 -07002113 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002114 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee1465db52009-09-23 17:17:35 -07002115 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002116 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002117 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002118 /* r1 now contains object->clazz */
2119 loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002120 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee1465db52009-09-23 17:17:35 -07002121 opRegReg(cUnit, kOpCmp, r1, r2);
2122 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2123 genRegCopy(cUnit, r0, r1);
2124 genRegCopy(cUnit, r1, r2);
2125 opReg(cUnit, kOpBlx, r3);
Elliott Hughes6a555132010-02-25 15:41:42 -08002126 dvmCompilerClobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002127 /* branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07002128 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07002129 target->defMask = ENCODE_ALL;
Bill Buzbeec6f10662010-02-09 11:16:15 -08002130 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002131 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002132 branch1->generic.target = (LIR *)target;
2133 branch2->generic.target = (LIR *)target;
2134 break;
2135 }
2136 case OP_IGET_WIDE:
2137 genIGetWide(cUnit, mir, fieldOffset);
2138 break;
2139 case OP_IGET:
2140 case OP_IGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002141 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002142 break;
2143 case OP_IGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07002144 genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002145 break;
2146 case OP_IGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002147 genIGet(cUnit, mir, kSignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002148 break;
2149 case OP_IGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002150 genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002151 break;
2152 case OP_IGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002153 genIGet(cUnit, mir, kSignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002154 break;
2155 case OP_IPUT_WIDE:
2156 genIPutWide(cUnit, mir, fieldOffset);
2157 break;
2158 case OP_IPUT:
2159 case OP_IPUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002160 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002161 break;
2162 case OP_IPUT_SHORT:
2163 case OP_IPUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002164 genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002165 break;
2166 case OP_IPUT_BYTE:
2167 case OP_IPUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07002168 genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002169 break;
2170 default:
2171 return true;
2172 }
2173 return false;
2174}
2175
2176static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2177{
2178 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2179 int fieldOffset = mir->dalvikInsn.vC;
2180 switch (dalvikOpCode) {
2181 case OP_IGET_QUICK:
2182 case OP_IGET_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07002183 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002184 break;
2185 case OP_IPUT_QUICK:
2186 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07002187 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002188 break;
2189 case OP_IGET_WIDE_QUICK:
2190 genIGetWide(cUnit, mir, fieldOffset);
2191 break;
2192 case OP_IPUT_WIDE_QUICK:
2193 genIPutWide(cUnit, mir, fieldOffset);
2194 break;
2195 default:
2196 return true;
2197 }
2198 return false;
2199
2200}
2201
2202/* Compare agaist zero */
2203static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002204 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002205{
2206 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002207 ArmConditionCode cond;
Bill Buzbeec6f10662010-02-09 11:16:15 -08002208 RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2209 RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002210
Bill Buzbee1465db52009-09-23 17:17:35 -07002211 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
2212 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
2213 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002214
2215 switch (dalvikOpCode) {
2216 case OP_IF_EQ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002217 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002218 break;
2219 case OP_IF_NE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002220 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002221 break;
2222 case OP_IF_LT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002223 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002224 break;
2225 case OP_IF_GE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002226 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002227 break;
2228 case OP_IF_GT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002229 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002230 break;
2231 case OP_IF_LE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002232 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002233 break;
2234 default:
2235 cond = 0;
2236 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2237 dvmAbort();
2238 }
2239 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2240 /* This mostly likely will be optimized away in a later phase */
2241 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2242 return false;
2243}
2244
2245static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2246{
2247 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002248
2249 switch (opCode) {
2250 case OP_MOVE_16:
2251 case OP_MOVE_OBJECT_16:
2252 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002253 case OP_MOVE_OBJECT_FROM16: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002254 storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
2255 dvmCompilerGetSrc(cUnit, mir, 0));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002256 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002257 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002258 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002259 case OP_MOVE_WIDE_FROM16: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002260 storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
2261 dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002262 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002263 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002264 default:
2265 return true;
2266 }
2267 return false;
2268}
2269
2270static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2271{
2272 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002273 RegLocation rlSrc1;
2274 RegLocation rlSrc2;
2275 RegLocation rlDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002276
2277 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
Ben Cheng5d90c202009-11-22 23:31:11 -08002278 return genArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002279 }
2280
Bill Buzbee1465db52009-09-23 17:17:35 -07002281 /* APUTs have 3 sources and no targets */
2282 if (mir->ssaRep->numDefs == 0) {
2283 if (mir->ssaRep->numUses == 3) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002284 rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
2285 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
2286 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
Bill Buzbee1465db52009-09-23 17:17:35 -07002287 } else {
2288 assert(mir->ssaRep->numUses == 4);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002289 rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2290 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
2291 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
Bill Buzbee1465db52009-09-23 17:17:35 -07002292 }
2293 } else {
2294 /* Two sources and 1 dest. Deduce the operand sizes */
2295 if (mir->ssaRep->numUses == 4) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002296 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2297 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
Bill Buzbee1465db52009-09-23 17:17:35 -07002298 } else {
2299 assert(mir->ssaRep->numUses == 2);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002300 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2301 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002302 }
2303 if (mir->ssaRep->numDefs == 2) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002304 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002305 } else {
2306 assert(mir->ssaRep->numDefs == 1);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002307 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002308 }
2309 }
2310
2311
Ben Chengba4fc8b2009-06-01 13:00:29 -07002312 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002313 case OP_CMPL_FLOAT:
2314 case OP_CMPG_FLOAT:
2315 case OP_CMPL_DOUBLE:
2316 case OP_CMPG_DOUBLE:
Ben Cheng5d90c202009-11-22 23:31:11 -08002317 return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002318 case OP_CMP_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07002319 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002320 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002321 case OP_AGET_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002322 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002323 break;
2324 case OP_AGET:
2325 case OP_AGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002326 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002327 break;
2328 case OP_AGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07002329 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002330 break;
2331 case OP_AGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002332 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002333 break;
2334 case OP_AGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002335 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002336 break;
2337 case OP_AGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002338 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002339 break;
2340 case OP_APUT_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002341 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002342 break;
2343 case OP_APUT:
2344 case OP_APUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002345 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002346 break;
2347 case OP_APUT_SHORT:
2348 case OP_APUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002349 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002350 break;
2351 case OP_APUT_BYTE:
2352 case OP_APUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07002353 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002354 break;
2355 default:
2356 return true;
2357 }
2358 return false;
2359}
2360
Ben Cheng6c10a972009-10-29 14:39:18 -07002361/*
2362 * Find the matching case.
2363 *
2364 * return values:
2365 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
2366 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
2367 * r1 (high 32-bit): the branch offset of the matching case (only for indexes
2368 * above MAX_CHAINED_SWITCH_CASES).
2369 *
2370 * Instructions around the call are:
2371 *
2372 * mov r2, pc
2373 * blx &findPackedSwitchIndex
2374 * mov pc, r0
2375 * .align4
2376 * chaining cell for case 0 [8 bytes]
2377 * chaining cell for case 1 [8 bytes]
2378 * :
2379 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
2380 * chaining cell for case default [8 bytes]
2381 * noChain exit
2382 */
2383s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
2384{
2385 int size;
2386 int firstKey;
2387 const int *entries;
2388 int index;
2389 int jumpIndex;
2390 int caseDPCOffset = 0;
2391 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
2392 int chainingPC = (pc + 4) & ~3;
2393
2394 /*
2395 * Packed switch data format:
2396 * ushort ident = 0x0100 magic value
2397 * ushort size number of entries in the table
2398 * int first_key first (and lowest) switch case value
2399 * int targets[size] branch targets, relative to switch opcode
2400 *
2401 * Total size is (4+size*2) 16-bit code units.
2402 */
2403 size = switchData[1];
2404 assert(size > 0);
2405
2406 firstKey = switchData[2];
2407 firstKey |= switchData[3] << 16;
2408
2409
2410 /* The entries are guaranteed to be aligned on a 32-bit boundary;
2411 * we can treat them as a native int array.
2412 */
2413 entries = (const int*) &switchData[4];
2414 assert(((u4)entries & 0x3) == 0);
2415
2416 index = testVal - firstKey;
2417
2418 /* Jump to the default cell */
2419 if (index < 0 || index >= size) {
2420 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
2421 /* Jump to the non-chaining exit point */
2422 } else if (index >= MAX_CHAINED_SWITCH_CASES) {
2423 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
2424 caseDPCOffset = entries[index];
2425 /* Jump to the inline chaining cell */
2426 } else {
2427 jumpIndex = index;
2428 }
2429
2430 chainingPC += jumpIndex * 8;
2431 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
2432}
2433
2434/* See comments for findPackedSwitchIndex */
2435s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
2436{
2437 int size;
2438 const int *keys;
2439 const int *entries;
2440 int chainingPC = (pc + 4) & ~3;
2441 int i;
2442
2443 /*
2444 * Sparse switch data format:
2445 * ushort ident = 0x0200 magic value
2446 * ushort size number of entries in the table; > 0
2447 * int keys[size] keys, sorted low-to-high; 32-bit aligned
2448 * int targets[size] branch targets, relative to switch opcode
2449 *
2450 * Total size is (2+size*4) 16-bit code units.
2451 */
2452
2453 size = switchData[1];
2454 assert(size > 0);
2455
2456 /* The keys are guaranteed to be aligned on a 32-bit boundary;
2457 * we can treat them as a native int array.
2458 */
2459 keys = (const int*) &switchData[2];
2460 assert(((u4)keys & 0x3) == 0);
2461
2462 /* The entries are guaranteed to be aligned on a 32-bit boundary;
2463 * we can treat them as a native int array.
2464 */
2465 entries = keys + size;
2466 assert(((u4)entries & 0x3) == 0);
2467
2468 /*
2469 * Run through the list of keys, which are guaranteed to
2470 * be sorted low-to-high.
2471 *
2472 * Most tables have 3-4 entries. Few have more than 10. A binary
2473 * search here is probably not useful.
2474 */
2475 for (i = 0; i < size; i++) {
2476 int k = keys[i];
2477 if (k == testVal) {
2478 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
2479 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
2480 i : MAX_CHAINED_SWITCH_CASES + 1;
2481 chainingPC += jumpIndex * 8;
2482 return (((s8) entries[i]) << 32) | (u8) chainingPC;
2483 } else if (k > testVal) {
2484 break;
2485 }
2486 }
2487 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
2488}
2489
Ben Chengba4fc8b2009-06-01 13:00:29 -07002490static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2491{
2492 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2493 switch (dalvikOpCode) {
2494 case OP_FILL_ARRAY_DATA: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002495 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002496 // Making a call - use explicit registers
Bill Buzbeec6f10662010-02-09 11:16:15 -08002497 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002498 genExportPC(cUnit, mir);
2499 loadValueDirectFixed(cUnit, rlSrc, r0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002500 loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData);
Ben Cheng6c10a972009-10-29 14:39:18 -07002501 loadConstant(cUnit, r1,
2502 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
Bill Buzbee1465db52009-09-23 17:17:35 -07002503 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -08002504 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002505 /* generate a branch over if successful */
2506 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2507 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
2508 loadConstant(cUnit, r0,
2509 (int) (cUnit->method->insns + mir->offset));
2510 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2511 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2512 target->defMask = ENCODE_ALL;
2513 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002514 break;
2515 }
2516 /*
Ben Cheng6c10a972009-10-29 14:39:18 -07002517 * Compute the goto target of up to
2518 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
2519 * See the comment before findPackedSwitchIndex for the code layout.
Ben Chengba4fc8b2009-06-01 13:00:29 -07002520 */
2521 case OP_PACKED_SWITCH:
2522 case OP_SPARSE_SWITCH: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002523 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2524 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002525 loadValueDirectFixed(cUnit, rlSrc, r1);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002526 dvmCompilerLockAllTemps(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07002527 const u2 *switchData =
2528 cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
2529 u2 size = switchData[1];
2530
Ben Chengba4fc8b2009-06-01 13:00:29 -07002531 if (dalvikOpCode == OP_PACKED_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -07002532 loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002533 } else {
Ben Cheng6c10a972009-10-29 14:39:18 -07002534 loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002535 }
Ben Cheng6c10a972009-10-29 14:39:18 -07002536 /* r0 <- Addr of the switch data */
2537 loadConstant(cUnit, r0,
2538 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2539 /* r2 <- pc of the instruction following the blx */
2540 opRegReg(cUnit, kOpMov, r2, rpc);
Bill Buzbee1465db52009-09-23 17:17:35 -07002541 opReg(cUnit, kOpBlx, r4PC);
Elliott Hughes6a555132010-02-25 15:41:42 -08002542 dvmCompilerClobberCallRegs(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07002543 /* pc <- computed goto target */
2544 opRegReg(cUnit, kOpMov, rpc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002545 break;
2546 }
2547 default:
2548 return true;
2549 }
2550 return false;
2551}
2552
2553static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002554 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002555{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07002556 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002557 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002558
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07002559 if (bb->fallThrough != NULL)
2560 retChainingCell = &labelList[bb->fallThrough->id];
2561
Ben Chengba4fc8b2009-06-01 13:00:29 -07002562 DecodedInstruction *dInsn = &mir->dalvikInsn;
2563 switch (mir->dalvikInsn.opCode) {
2564 /*
2565 * calleeMethod = this->clazz->vtable[
2566 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2567 * ]
2568 */
2569 case OP_INVOKE_VIRTUAL:
2570 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002571 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002572 int methodIndex =
2573 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2574 methodIndex;
2575
2576 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2577 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2578 else
2579 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2580
Ben Cheng38329f52009-07-07 14:19:20 -07002581 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2582 retChainingCell,
2583 predChainingCell,
2584 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002585 break;
2586 }
2587 /*
2588 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2589 * ->pResMethods[BBBB]->methodIndex]
2590 */
2591 /* TODO - not excersized in RunPerf.jar */
2592 case OP_INVOKE_SUPER:
2593 case OP_INVOKE_SUPER_RANGE: {
2594 int mIndex = cUnit->method->clazz->pDvmDex->
2595 pResMethods[dInsn->vB]->methodIndex;
2596 const Method *calleeMethod =
2597 cUnit->method->clazz->super->vtable[mIndex];
2598
2599 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2600 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2601 else
2602 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2603
2604 /* r0 = calleeMethod */
2605 loadConstant(cUnit, r0, (int) calleeMethod);
2606
Ben Cheng38329f52009-07-07 14:19:20 -07002607 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2608 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002609 break;
2610 }
2611 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2612 case OP_INVOKE_DIRECT:
2613 case OP_INVOKE_DIRECT_RANGE: {
2614 const Method *calleeMethod =
2615 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2616
2617 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2618 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2619 else
2620 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2621
2622 /* r0 = calleeMethod */
2623 loadConstant(cUnit, r0, (int) calleeMethod);
2624
Ben Cheng38329f52009-07-07 14:19:20 -07002625 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2626 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002627 break;
2628 }
2629 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2630 case OP_INVOKE_STATIC:
2631 case OP_INVOKE_STATIC_RANGE: {
2632 const Method *calleeMethod =
2633 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2634
2635 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2636 genProcessArgsNoRange(cUnit, mir, dInsn,
2637 NULL /* no null check */);
2638 else
2639 genProcessArgsRange(cUnit, mir, dInsn,
2640 NULL /* no null check */);
2641
2642 /* r0 = calleeMethod */
2643 loadConstant(cUnit, r0, (int) calleeMethod);
2644
Ben Cheng38329f52009-07-07 14:19:20 -07002645 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2646 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002647 break;
2648 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002649 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -07002650 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2651 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07002652 *
2653 * Given "invoke-interface {v0}", the following is the generated code:
2654 *
2655 * 0x426a9abe : ldr r0, [r5, #0] --+
2656 * 0x426a9ac0 : mov r7, r5 |
2657 * 0x426a9ac2 : sub r7, #24 |
2658 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2659 * 0x426a9ac6 : beq 0x426a9afe |
2660 * 0x426a9ac8 : stmia r7, <r0> --+
2661 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2662 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
2663 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
2664 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
2665 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
2666 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
2667 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
Ben Chenga8e64a72009-10-20 13:01:36 -07002668 * 0x426a9ad8 : mov r8, r1 --+
2669 * 0x426a9ada : mov r9, r2 |
2670 * 0x426a9adc : mov r10, r3 |
Ben Cheng38329f52009-07-07 14:19:20 -07002671 * 0x426a9ade : mov r0, r3 |
2672 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
2673 * 0x426a9ae2 : ldr r2, [pc, #76] |
2674 * 0x426a9ae4 : ldr r3, [pc, #68] |
2675 * 0x426a9ae6 : ldr r7, [pc, #64] |
2676 * 0x426a9ae8 : blx r7 --+
Ben Chenga8e64a72009-10-20 13:01:36 -07002677 * 0x426a9aea : mov r1, r8 --> r1 <- rechain count
Ben Cheng38329f52009-07-07 14:19:20 -07002678 * 0x426a9aec : cmp r1, #0 --> compare against 0
2679 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
2680 * 0x426a9af0 : ldr r7, [r6, #96] --+
Ben Chenga8e64a72009-10-20 13:01:36 -07002681 * 0x426a9af2 : mov r2, r9 | dvmJitToPatchPredictedChain
2682 * 0x426a9af4 : mov r3, r10 |
Ben Cheng38329f52009-07-07 14:19:20 -07002683 * 0x426a9af6 : blx r7 --+
2684 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
2685 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2686 * 0x426a9afc : blx_2 see above --+
2687 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
2688 * 0x426a9afe (0042): ldr r0, [pc, #52]
2689 * Exception_Handling:
2690 * 0x426a9b00 (0044): ldr r1, [r6, #84]
2691 * 0x426a9b02 (0046): blx r1
2692 * 0x426a9b04 (0048): .align4
2693 * -------- chaining cell (hot): 0x0021
2694 * 0x426a9b04 (0048): ldr r0, [r6, #92]
2695 * 0x426a9b06 (004a): blx r0
2696 * 0x426a9b08 (004c): data 0x7872(30834)
2697 * 0x426a9b0a (004e): data 0x428b(17035)
2698 * 0x426a9b0c (0050): .align4
2699 * -------- chaining cell (predicted)
2700 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
2701 * 0x426a9b0e (0052): data 0x0000(0)
2702 * 0x426a9b10 (0054): data 0x0000(0) --> class
2703 * 0x426a9b12 (0056): data 0x0000(0)
2704 * 0x426a9b14 (0058): data 0x0000(0) --> method
2705 * 0x426a9b16 (005a): data 0x0000(0)
2706 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
2707 * 0x426a9b1a (005e): data 0x0000(0)
2708 * 0x426a9b28 (006c): .word (0xad0392a5)
2709 * 0x426a9b2c (0070): .word (0x6e750)
2710 * 0x426a9b30 (0074): .word (0x4109a618)
2711 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002712 */
2713 case OP_INVOKE_INTERFACE:
2714 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002715 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002716 int methodIndex = dInsn->vB;
2717
Bill Buzbee1465db52009-09-23 17:17:35 -07002718 /* Ensure that nothing is both live and dirty */
Bill Buzbeec6f10662010-02-09 11:16:15 -08002719 dvmCompilerFlushAllRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002720
Ben Chengba4fc8b2009-06-01 13:00:29 -07002721 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2722 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2723 else
2724 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2725
Ben Cheng38329f52009-07-07 14:19:20 -07002726 /* "this" is already left in r0 by genProcessArgs* */
2727
2728 /* r4PC = dalvikCallsite */
2729 loadConstant(cUnit, r4PC,
2730 (int) (cUnit->method->insns + mir->offset));
2731
2732 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002733 ArmLIR *addrRetChain =
Bill Buzbee1465db52009-09-23 17:17:35 -07002734 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002735 addrRetChain->generic.target = (LIR *) retChainingCell;
2736
2737 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002738 ArmLIR *predictedChainingCell =
Bill Buzbee1465db52009-09-23 17:17:35 -07002739 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002740 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2741
2742 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2743
2744 /* return through lr - jump to the chaining cell */
2745 genUnconditionalBranch(cUnit, predChainingCell);
2746
2747 /*
2748 * null-check on "this" may have been eliminated, but we still need
2749 * a PC-reconstruction label for stack overflow bailout.
2750 */
2751 if (pcrLabel == NULL) {
2752 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002753 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07002754 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07002755 pcrLabel->operands[0] = dPC;
2756 pcrLabel->operands[1] = mir->offset;
2757 /* Insert the place holder to the growable list */
2758 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2759 }
2760
2761 /* return through lr+2 - punt to the interpreter */
2762 genUnconditionalBranch(cUnit, pcrLabel);
2763
2764 /*
2765 * return through lr+4 - fully resolve the callee method.
2766 * r1 <- count
2767 * r2 <- &predictedChainCell
2768 * r3 <- this->class
2769 * r4 <- dPC
2770 * r7 <- this->class->vtable
2771 */
2772
2773 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee1465db52009-09-23 17:17:35 -07002774 genRegCopy(cUnit, r8, r1);
2775 genRegCopy(cUnit, r9, r2);
2776 genRegCopy(cUnit, r10, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002777
Ben Chengba4fc8b2009-06-01 13:00:29 -07002778 /* r0 now contains this->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07002779 genRegCopy(cUnit, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002780
2781 /* r1 = BBBB */
2782 loadConstant(cUnit, r1, dInsn->vB);
2783
2784 /* r2 = method (caller) */
2785 loadConstant(cUnit, r2, (int) cUnit->method);
2786
2787 /* r3 = pDvmDex */
2788 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2789
2790 loadConstant(cUnit, r7,
2791 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee1465db52009-09-23 17:17:35 -07002792 opReg(cUnit, kOpBlx, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002793
2794 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2795
Bill Buzbee1465db52009-09-23 17:17:35 -07002796 genRegCopy(cUnit, r1, r8);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002797
Ben Cheng38329f52009-07-07 14:19:20 -07002798 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07002799 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002800
Bill Buzbee1465db52009-09-23 17:17:35 -07002801 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07002802
Bill Buzbee270c1d62009-08-13 16:58:07 -07002803 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2804 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002805
Bill Buzbee1465db52009-09-23 17:17:35 -07002806 genRegCopy(cUnit, r2, r9);
2807 genRegCopy(cUnit, r3, r10);
Ben Cheng38329f52009-07-07 14:19:20 -07002808
2809 /*
2810 * r0 = calleeMethod
2811 * r2 = &predictedChainingCell
2812 * r3 = class
2813 *
2814 * &returnChainingCell has been loaded into r1 but is not needed
2815 * when patching the chaining cell and will be clobbered upon
2816 * returning so it will be reconstructed again.
2817 */
Bill Buzbee1465db52009-09-23 17:17:35 -07002818 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002819
2820 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002821 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002822 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07002823
2824 bypassRechaining->generic.target = (LIR *) addrRetChain;
2825
Ben Chengba4fc8b2009-06-01 13:00:29 -07002826 /*
2827 * r0 = this, r1 = calleeMethod,
2828 * r1 = &ChainingCell,
2829 * r4PC = callsiteDPC,
2830 */
2831 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2832#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07002833 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002834#endif
2835 /* Handle exceptions using the interpreter */
2836 genTrap(cUnit, mir->offset, pcrLabel);
2837 break;
2838 }
2839 /* NOP */
2840 case OP_INVOKE_DIRECT_EMPTY: {
2841 return false;
2842 }
2843 case OP_FILLED_NEW_ARRAY:
2844 case OP_FILLED_NEW_ARRAY_RANGE: {
2845 /* Just let the interpreter deal with these */
2846 genInterpSingleStep(cUnit, mir);
2847 break;
2848 }
2849 default:
2850 return true;
2851 }
2852 return false;
2853}
2854
2855static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002856 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002857{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002858 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
2859 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2860 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002861
2862 DecodedInstruction *dInsn = &mir->dalvikInsn;
2863 switch (mir->dalvikInsn.opCode) {
2864 /* calleeMethod = this->clazz->vtable[BBBB] */
2865 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2866 case OP_INVOKE_VIRTUAL_QUICK: {
2867 int methodIndex = dInsn->vB;
2868 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2869 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2870 else
2871 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2872
Ben Cheng38329f52009-07-07 14:19:20 -07002873 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2874 retChainingCell,
2875 predChainingCell,
2876 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002877 break;
2878 }
2879 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2880 case OP_INVOKE_SUPER_QUICK:
2881 case OP_INVOKE_SUPER_QUICK_RANGE: {
2882 const Method *calleeMethod =
2883 cUnit->method->clazz->super->vtable[dInsn->vB];
2884
2885 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2886 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2887 else
2888 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2889
2890 /* r0 = calleeMethod */
2891 loadConstant(cUnit, r0, (int) calleeMethod);
2892
Ben Cheng38329f52009-07-07 14:19:20 -07002893 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2894 calleeMethod);
2895 /* Handle exceptions using the interpreter */
2896 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002897 break;
2898 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002899 default:
2900 return true;
2901 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002902 return false;
2903}
2904
2905/*
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002906 * This operation is complex enough that we'll do it partly inline
2907 * and partly with a handler. NOTE: the handler uses hardcoded
2908 * values for string object offsets and must be revisitied if the
2909 * layout changes.
2910 */
2911static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
2912{
2913#if defined(USE_GLOBAL_STRING_DEFS)
2914 return false;
2915#else
2916 ArmLIR *rollback;
Bill Buzbeec6f10662010-02-09 11:16:15 -08002917 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
2918 RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002919
2920 loadValueDirectFixed(cUnit, rlThis, r0);
2921 loadValueDirectFixed(cUnit, rlComp, r1);
2922 /* Test objects for NULL */
2923 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
2924 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
2925 /*
2926 * TUNING: we could check for object pointer equality before invoking
2927 * handler. Unclear whether the gain would be worth the added code size
2928 * expansion.
2929 */
2930 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002931 storeValue(cUnit, inlinedTarget(cUnit, mir, false),
2932 dvmCompilerGetReturn(cUnit));
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002933 return true;
2934#endif
2935}
2936
2937static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
2938{
2939#if defined(USE_GLOBAL_STRING_DEFS)
2940 return false;
2941#else
Bill Buzbeec6f10662010-02-09 11:16:15 -08002942 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
2943 RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002944
2945 loadValueDirectFixed(cUnit, rlThis, r0);
2946 loadValueDirectFixed(cUnit, rlChar, r1);
2947 if (!singleI) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002948 RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002949 loadValueDirectFixed(cUnit, rlStart, r2);
2950 } else {
2951 loadConstant(cUnit, r2, 0);
2952 }
2953 /* Test objects for NULL */
2954 genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
2955 genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002956 storeValue(cUnit, inlinedTarget(cUnit, mir, false),
2957 dvmCompilerGetReturn(cUnit));
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002958 return true;
2959#endif
2960}
2961
2962
2963/*
Bill Buzbeece46c942009-11-20 15:41:34 -08002964 * NOTE: Handles both range and non-range versions (arguments
2965 * have already been normalized by this point).
Ben Chengba4fc8b2009-06-01 13:00:29 -07002966 */
Bill Buzbeece46c942009-11-20 15:41:34 -08002967static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002968{
2969 DecodedInstruction *dInsn = &mir->dalvikInsn;
2970 switch( mir->dalvikInsn.opCode) {
Bill Buzbeece46c942009-11-20 15:41:34 -08002971 case OP_EXECUTE_INLINE_RANGE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002972 case OP_EXECUTE_INLINE: {
2973 unsigned int i;
2974 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002975 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002976 int operation = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07002977 int tReg1;
2978 int tReg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002979 switch (operation) {
2980 case INLINE_EMPTYINLINEMETHOD:
2981 return false; /* Nop */
2982 case INLINE_STRING_LENGTH:
2983 return genInlinedStringLength(cUnit, mir);
2984 case INLINE_MATH_ABS_INT:
2985 return genInlinedAbsInt(cUnit, mir);
2986 case INLINE_MATH_ABS_LONG:
2987 return genInlinedAbsLong(cUnit, mir);
2988 case INLINE_MATH_MIN_INT:
2989 return genInlinedMinMaxInt(cUnit, mir, true);
2990 case INLINE_MATH_MAX_INT:
2991 return genInlinedMinMaxInt(cUnit, mir, false);
2992 case INLINE_STRING_CHARAT:
2993 return genInlinedStringCharAt(cUnit, mir);
2994 case INLINE_MATH_SQRT:
2995 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07002996 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002997 else
2998 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002999 case INLINE_MATH_ABS_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003000 if (genInlinedAbsFloat(cUnit, mir))
3001 return false;
3002 else
3003 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003004 case INLINE_MATH_ABS_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003005 if (genInlinedAbsDouble(cUnit, mir))
3006 return false;
3007 else
3008 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003009 case INLINE_STRING_COMPARETO:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003010 if (genInlinedCompareTo(cUnit, mir))
3011 return false;
3012 else
3013 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003014 case INLINE_STRING_INDEXOF_I:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003015 if (genInlinedIndexOf(cUnit, mir, true /* I */))
3016 return false;
3017 else
3018 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003019 case INLINE_STRING_INDEXOF_II:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003020 if (genInlinedIndexOf(cUnit, mir, false /* I */))
3021 return false;
3022 else
3023 break;
3024 case INLINE_STRING_EQUALS:
3025 case INLINE_MATH_COS:
3026 case INLINE_MATH_SIN:
3027 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003028 default:
3029 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003030 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08003031 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Elliott Hughes6a555132010-02-25 15:41:42 -08003032 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbeec6f10662010-02-09 11:16:15 -08003033 dvmCompilerClobber(cUnit, r4PC);
3034 dvmCompilerClobber(cUnit, r7);
Bill Buzbee1465db52009-09-23 17:17:35 -07003035 opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3036 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003037 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
Bill Buzbee1465db52009-09-23 17:17:35 -07003038 genExportPC(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003039 for (i=0; i < dInsn->vA; i++) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003040 loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003041 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003042 opReg(cUnit, kOpBlx, r4PC);
3043 opRegImm(cUnit, kOpAdd, r13, 8);
Bill Buzbeece46c942009-11-20 15:41:34 -08003044 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3045 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3046 loadConstant(cUnit, r0,
3047 (int) (cUnit->method->insns + mir->offset));
3048 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3049 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3050 target->defMask = ENCODE_ALL;
3051 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003052 break;
3053 }
3054 default:
3055 return true;
3056 }
3057 return false;
3058}
3059
3060static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3061{
Bill Buzbee1465db52009-09-23 17:17:35 -07003062 //TUNING: We're using core regs here - not optimal when target is a double
Bill Buzbeec6f10662010-02-09 11:16:15 -08003063 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
3064 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003065 loadConstantValue(cUnit, rlResult.lowReg,
3066 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3067 loadConstantValue(cUnit, rlResult.highReg,
3068 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3069 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003070 return false;
3071}
3072
Ben Chengba4fc8b2009-06-01 13:00:29 -07003073/*
3074 * The following are special processing routines that handle transfer of
3075 * controls between compiled code and the interpreter. Certain VM states like
3076 * Dalvik PC and special-purpose registers are reconstructed here.
3077 */
3078
Ben Cheng1efc9c52009-06-08 18:25:27 -07003079/* Chaining cell for code that may need warmup. */
3080static void handleNormalChainingCell(CompilationUnit *cUnit,
3081 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003082{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003083 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3084 jitToInterpEntries.dvmJitToInterpNormal), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003085 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003086 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3087}
3088
3089/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003090 * Chaining cell for instructions that immediately following already translated
3091 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003092 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003093static void handleHotChainingCell(CompilationUnit *cUnit,
3094 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003095{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003096 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
Ben Cheng40094c12010-02-24 20:58:44 -08003097 jitToInterpEntries.dvmJitToInterpTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003098 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003099 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3100}
3101
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003102#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003103/* Chaining cell for branches that branch back into the same basic block */
3104static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3105 unsigned int offset)
3106{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003107#if defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07003108 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Ben Cheng40094c12010-02-24 20:58:44 -08003109 offsetof(InterpState,
3110 jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003111#else
Bill Buzbee1465db52009-09-23 17:17:35 -07003112 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003113 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3114#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07003115 newLIR1(cUnit, kThumbBlxR, r0);
Jeff Hao97319a82009-08-12 16:57:15 -07003116 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3117}
3118
3119#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003120/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003121static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3122 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003123{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003124 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
Ben Cheng40094c12010-02-24 20:58:44 -08003125 jitToInterpEntries.dvmJitToInterpTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003126 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003127 addWordData(cUnit, (int) (callee->insns), true);
3128}
3129
Ben Cheng38329f52009-07-07 14:19:20 -07003130/* Chaining cell for monomorphic method invocations. */
3131static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3132{
3133
3134 /* Should not be executed in the initial state */
3135 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3136 /* To be filled: class */
3137 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3138 /* To be filled: method */
3139 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3140 /*
3141 * Rechain count. The initial value of 0 here will trigger chaining upon
3142 * the first invocation of this callsite.
3143 */
3144 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3145}
3146
Ben Chengba4fc8b2009-06-01 13:00:29 -07003147/* Load the Dalvik PC into r0 and jump to the specified target */
3148static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003149 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003150{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003151 ArmLIR **pcrLabel =
3152 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003153 int numElems = cUnit->pcReconstructionList.numUsed;
3154 int i;
3155 for (i = 0; i < numElems; i++) {
3156 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3157 /* r0 = dalvik PC */
3158 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3159 genUnconditionalBranch(cUnit, targetLabel);
3160 }
3161}
3162
Bill Buzbee1465db52009-09-23 17:17:35 -07003163static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
3164 "kMirOpPhi",
3165 "kMirOpNullNRangeUpCheck",
3166 "kMirOpNullNRangeDownCheck",
3167 "kMirOpLowerBound",
3168 "kMirOpPunt",
Ben Cheng4238ec22009-08-24 16:32:22 -07003169};
3170
3171/*
3172 * vA = arrayReg;
3173 * vB = idxReg;
3174 * vC = endConditionReg;
3175 * arg[0] = maxC
3176 * arg[1] = minC
3177 * arg[2] = loopBranchConditionCode
3178 */
3179static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3180{
Bill Buzbee1465db52009-09-23 17:17:35 -07003181 /*
3182 * NOTE: these synthesized blocks don't have ssa names assigned
3183 * for Dalvik registers. However, because they dominate the following
3184 * blocks we can simply use the Dalvik name w/ subscript 0 as the
3185 * ssa name.
3186 */
Ben Cheng4238ec22009-08-24 16:32:22 -07003187 DecodedInstruction *dInsn = &mir->dalvikInsn;
3188 const int lenOffset = offsetof(ArrayObject, length);
Ben Cheng4238ec22009-08-24 16:32:22 -07003189 const int maxC = dInsn->arg[0];
3190 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07003191 int regLength;
3192 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3193 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
Ben Cheng4238ec22009-08-24 16:32:22 -07003194
3195 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07003196 rlArray = loadValue(cUnit, rlArray, kCoreReg);
3197 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
3198 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003199 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3200
3201 /* regLength <- len(arrayRef) */
Bill Buzbeec6f10662010-02-09 11:16:15 -08003202 regLength = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003203 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07003204
3205 int delta = maxC;
3206 /*
3207 * If the loop end condition is ">=" instead of ">", then the largest value
3208 * of the index is "endCondition - 1".
3209 */
3210 if (dInsn->arg[2] == OP_IF_GE) {
3211 delta--;
3212 }
3213
3214 if (delta) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003215 int tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003216 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
3217 rlIdxEnd.lowReg = tReg;
Bill Buzbeec6f10662010-02-09 11:16:15 -08003218 dvmCompilerFreeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003219 }
3220 /* Punt if "regIdxEnd < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003221 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07003222 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003223}
3224
3225/*
3226 * vA = arrayReg;
3227 * vB = idxReg;
3228 * vC = endConditionReg;
3229 * arg[0] = maxC
3230 * arg[1] = minC
3231 * arg[2] = loopBranchConditionCode
3232 */
3233static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3234{
3235 DecodedInstruction *dInsn = &mir->dalvikInsn;
3236 const int lenOffset = offsetof(ArrayObject, length);
Bill Buzbeec6f10662010-02-09 11:16:15 -08003237 const int regLength = dvmCompilerAllocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07003238 const int maxC = dInsn->arg[0];
3239 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07003240 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3241 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
Ben Cheng4238ec22009-08-24 16:32:22 -07003242
3243 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07003244 rlArray = loadValue(cUnit, rlArray, kCoreReg);
3245 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
3246 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003247 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3248
3249 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07003250 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07003251
3252 if (maxC) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003253 int tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003254 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
3255 rlIdxInit.lowReg = tReg;
Bill Buzbeec6f10662010-02-09 11:16:15 -08003256 dvmCompilerFreeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003257 }
3258
3259 /* Punt if "regIdxInit < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003260 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07003261 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003262}
3263
3264/*
3265 * vA = idxReg;
3266 * vB = minC;
3267 */
3268static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3269{
3270 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -07003271 const int minC = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07003272 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
Ben Cheng4238ec22009-08-24 16:32:22 -07003273
3274 /* regIdx <- initial index value */
Bill Buzbee1465db52009-09-23 17:17:35 -07003275 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003276
3277 /* Punt if "regIdxInit + minC >= 0" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003278 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003279 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3280}
3281
3282/* Extended MIR instructions like PHI */
3283static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3284{
Bill Buzbee1465db52009-09-23 17:17:35 -07003285 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
Ben Cheng4238ec22009-08-24 16:32:22 -07003286 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3287 false);
3288 strcpy(msg, extendedMIROpNames[opOffset]);
Bill Buzbee1465db52009-09-23 17:17:35 -07003289 newLIR1(cUnit, kArmPseudoExtended, (int) msg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003290
3291 switch (mir->dalvikInsn.opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003292 case kMirOpPhi: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003293 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07003294 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07003295 break;
3296 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003297 case kMirOpNullNRangeUpCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003298 genHoistedChecksForCountUpLoop(cUnit, mir);
3299 break;
3300 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003301 case kMirOpNullNRangeDownCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003302 genHoistedChecksForCountDownLoop(cUnit, mir);
3303 break;
3304 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003305 case kMirOpLowerBound: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003306 genHoistedLowerBoundCheck(cUnit, mir);
3307 break;
3308 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003309 case kMirOpPunt: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003310 genUnconditionalBranch(cUnit,
3311 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3312 break;
3313 }
3314 default:
3315 break;
3316 }
3317}
3318
3319/*
3320 * Create a PC-reconstruction cell for the starting offset of this trace.
3321 * Since the PCR cell is placed near the end of the compiled code which is
3322 * usually out of range for a conditional branch, we put two branches (one
3323 * branch over to the loop body and one layover branch to the actual PCR) at the
3324 * end of the entry block.
3325 */
3326static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3327 ArmLIR *bodyLabel)
3328{
3329 /* Set up the place holder to reconstruct this Dalvik PC */
3330 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003331 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng4238ec22009-08-24 16:32:22 -07003332 pcrLabel->operands[0] =
3333 (int) (cUnit->method->insns + entry->startOffset);
3334 pcrLabel->operands[1] = entry->startOffset;
3335 /* Insert the place holder to the growable list */
3336 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3337
3338 /*
3339 * Next, create two branches - one branch over to the loop body and the
3340 * other branch to the PCR cell to punt.
3341 */
3342 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003343 branchToBody->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07003344 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003345 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07003346 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3347
3348 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003349 branchToPCR->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07003350 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003351 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003352 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3353}
3354
Ben Chengba4fc8b2009-06-01 13:00:29 -07003355void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3356{
3357 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003358 ArmLIR *labelList =
3359 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengcec26f62010-01-15 15:29:33 -08003360 GrowableList chainingListByType[kChainingCellGap];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003361 int i;
3362
3363 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003364 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003365 */
Ben Chengcec26f62010-01-15 15:29:33 -08003366 for (i = 0; i < kChainingCellGap; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07003367 dvmInitGrowableList(&chainingListByType[i], 2);
3368 }
3369
3370 BasicBlock **blockList = cUnit->blockList;
3371
Bill Buzbee6e963e12009-06-17 16:56:19 -07003372 if (cUnit->executionCount) {
3373 /*
3374 * Reserve 6 bytes at the beginning of the trace
3375 * +----------------------------+
3376 * | execution count (4 bytes) |
3377 * +----------------------------+
3378 * | chain cell offset (2 bytes)|
3379 * +----------------------------+
3380 * ...and then code to increment the execution
3381 * count:
3382 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3383 * sub r0, #10 @ back up to addr of executionCount
3384 * ldr r1, [r0]
3385 * add r1, #1
3386 * str r1, [r0]
3387 */
Bill Buzbee1465db52009-09-23 17:17:35 -07003388 newLIR1(cUnit, kArm16BitData, 0);
3389 newLIR1(cUnit, kArm16BitData, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003390 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07003391 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003392 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003393 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee1465db52009-09-23 17:17:35 -07003394 newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
3395 newLIR2(cUnit, kThumbSubRI8, r0, 10);
3396 newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
3397 newLIR2(cUnit, kThumbAddRI8, r1, 1);
3398 newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003399 } else {
3400 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003401 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07003402 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003403 cUnit->headerSize = 2;
3404 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003405
Ben Chengba4fc8b2009-06-01 13:00:29 -07003406 /* Handle the content in each basic block */
3407 for (i = 0; i < cUnit->numBlocks; i++) {
3408 blockList[i]->visited = true;
3409 MIR *mir;
3410
3411 labelList[i].operands[0] = blockList[i]->startOffset;
3412
Ben Chengcec26f62010-01-15 15:29:33 -08003413 if (blockList[i]->blockType >= kChainingCellGap) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07003414 /*
3415 * Append the label pseudo LIR first. Chaining cells will be handled
3416 * separately afterwards.
3417 */
3418 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3419 }
3420
Bill Buzbee1465db52009-09-23 17:17:35 -07003421 if (blockList[i]->blockType == kEntryBlock) {
3422 labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07003423 if (blockList[i]->firstMIRInsn == NULL) {
3424 continue;
3425 } else {
3426 setupLoopEntryBlock(cUnit, blockList[i],
3427 &labelList[blockList[i]->fallThrough->id]);
3428 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003429 } else if (blockList[i]->blockType == kExitBlock) {
3430 labelList[i].opCode = ARM_PSEUDO_kExitBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07003431 goto gen_fallthrough;
Bill Buzbee1465db52009-09-23 17:17:35 -07003432 } else if (blockList[i]->blockType == kDalvikByteCode) {
3433 labelList[i].opCode = kArmPseudoNormalBlockLabel;
Ben Chenge9695e52009-06-16 16:11:47 -07003434 /* Reset the register state */
Bill Buzbeec6f10662010-02-09 11:16:15 -08003435 dvmCompilerResetRegPool(cUnit);
3436 dvmCompilerClobberAllRegs(cUnit);
3437 dvmCompilerResetNullCheck(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003438 } else {
3439 switch (blockList[i]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003440 case kChainingCellNormal:
3441 labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003442 /* handle the codegen later */
3443 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003444 &chainingListByType[kChainingCellNormal], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003445 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003446 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07003447 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003448 ARM_PSEUDO_kChainingCellInvokeSingleton;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003449 labelList[i].operands[0] =
3450 (int) blockList[i]->containingMethod;
3451 /* handle the codegen later */
3452 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003453 &chainingListByType[kChainingCellInvokeSingleton],
Ben Cheng38329f52009-07-07 14:19:20 -07003454 (void *) i);
3455 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003456 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07003457 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003458 ARM_PSEUDO_kChainingCellInvokePredicted;
Ben Cheng38329f52009-07-07 14:19:20 -07003459 /* handle the codegen later */
3460 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003461 &chainingListByType[kChainingCellInvokePredicted],
Ben Cheng38329f52009-07-07 14:19:20 -07003462 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003463 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003464 case kChainingCellHot:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003465 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003466 ARM_PSEUDO_kChainingCellHot;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003467 /* handle the codegen later */
3468 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003469 &chainingListByType[kChainingCellHot],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003470 (void *) i);
3471 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003472 case kPCReconstruction:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003473 /* Make sure exception handling block is next */
3474 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003475 ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003476 assert (i == cUnit->numBlocks - 2);
3477 handlePCReconstruction(cUnit, &labelList[i+1]);
3478 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003479 case kExceptionHandling:
3480 labelList[i].opCode = kArmPseudoEHBlockLabel;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003481 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003482 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3483 jitToInterpEntries.dvmJitToInterpPunt),
3484 r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07003485 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003486 }
3487 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003488#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07003489 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07003490 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003491 ARM_PSEUDO_kChainingCellBackwardBranch;
Jeff Hao97319a82009-08-12 16:57:15 -07003492 /* handle the codegen later */
3493 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003494 &chainingListByType[kChainingCellBackwardBranch],
Jeff Hao97319a82009-08-12 16:57:15 -07003495 (void *) i);
3496 break;
3497#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003498 default:
3499 break;
3500 }
3501 continue;
3502 }
Ben Chenge9695e52009-06-16 16:11:47 -07003503
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003504 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003505
Ben Chengba4fc8b2009-06-01 13:00:29 -07003506 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003507
Bill Buzbeec6f10662010-02-09 11:16:15 -08003508 dvmCompilerResetRegPool(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003509 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003510 dvmCompilerClobberAllRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003511 }
3512
3513 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003514 dvmCompilerResetDefTracking(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003515 }
3516
3517 if (mir->dalvikInsn.opCode >= kMirOpFirst) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003518 handleExtendedMIR(cUnit, mir);
3519 continue;
3520 }
3521
Bill Buzbee1465db52009-09-23 17:17:35 -07003522
Ben Chengba4fc8b2009-06-01 13:00:29 -07003523 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3524 InstructionFormat dalvikFormat =
3525 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003526 ArmLIR *boundaryLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07003527 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
Ben Chengccd6c012009-10-15 14:52:45 -07003528 mir->offset,
3529 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
3530 );
Ben Cheng4238ec22009-08-24 16:32:22 -07003531 if (mir->ssaRep) {
3532 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07003533 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07003534 }
3535
Ben Chenge9695e52009-06-16 16:11:47 -07003536 /* Remember the first LIR for this block */
3537 if (headLIR == NULL) {
3538 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07003539 /* Set the first boundaryLIR as a scheduling barrier */
3540 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07003541 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003542
Ben Chengba4fc8b2009-06-01 13:00:29 -07003543 bool notHandled;
3544 /*
3545 * Debugging: screen the opcode first to see if it is in the
3546 * do[-not]-compile list
3547 */
3548 bool singleStepMe =
3549 gDvmJit.includeSelectedOp !=
3550 ((gDvmJit.opList[dalvikOpCode >> 3] &
3551 (1 << (dalvikOpCode & 0x7))) !=
3552 0);
3553 if (singleStepMe || cUnit->allSingleStep) {
3554 notHandled = false;
3555 genInterpSingleStep(cUnit, mir);
3556 } else {
3557 opcodeCoverage[dalvikOpCode]++;
3558 switch (dalvikFormat) {
3559 case kFmt10t:
3560 case kFmt20t:
3561 case kFmt30t:
3562 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3563 mir, blockList[i], labelList);
3564 break;
3565 case kFmt10x:
3566 notHandled = handleFmt10x(cUnit, mir);
3567 break;
3568 case kFmt11n:
3569 case kFmt31i:
3570 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3571 break;
3572 case kFmt11x:
3573 notHandled = handleFmt11x(cUnit, mir);
3574 break;
3575 case kFmt12x:
3576 notHandled = handleFmt12x(cUnit, mir);
3577 break;
3578 case kFmt20bc:
3579 notHandled = handleFmt20bc(cUnit, mir);
3580 break;
3581 case kFmt21c:
3582 case kFmt31c:
3583 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3584 break;
3585 case kFmt21h:
3586 notHandled = handleFmt21h(cUnit, mir);
3587 break;
3588 case kFmt21s:
3589 notHandled = handleFmt21s(cUnit, mir);
3590 break;
3591 case kFmt21t:
3592 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3593 labelList);
3594 break;
3595 case kFmt22b:
3596 case kFmt22s:
3597 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3598 break;
3599 case kFmt22c:
3600 notHandled = handleFmt22c(cUnit, mir);
3601 break;
3602 case kFmt22cs:
3603 notHandled = handleFmt22cs(cUnit, mir);
3604 break;
3605 case kFmt22t:
3606 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3607 labelList);
3608 break;
3609 case kFmt22x:
3610 case kFmt32x:
3611 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3612 break;
3613 case kFmt23x:
3614 notHandled = handleFmt23x(cUnit, mir);
3615 break;
3616 case kFmt31t:
3617 notHandled = handleFmt31t(cUnit, mir);
3618 break;
3619 case kFmt3rc:
3620 case kFmt35c:
3621 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3622 labelList);
3623 break;
3624 case kFmt3rms:
3625 case kFmt35ms:
3626 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3627 labelList);
3628 break;
3629 case kFmt3inline:
Andy McFaddenb0a05412009-11-19 10:23:41 -08003630 case kFmt3rinline:
Bill Buzbeece46c942009-11-20 15:41:34 -08003631 notHandled = handleExecuteInline(cUnit, mir);
Andy McFaddenb0a05412009-11-19 10:23:41 -08003632 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003633 case kFmt51l:
3634 notHandled = handleFmt51l(cUnit, mir);
3635 break;
3636 default:
3637 notHandled = true;
3638 break;
3639 }
3640 }
3641 if (notHandled) {
3642 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3643 mir->offset,
3644 dalvikOpCode, getOpcodeName(dalvikOpCode),
3645 dalvikFormat);
3646 dvmAbort();
3647 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003648 }
3649 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003650
Bill Buzbee1465db52009-09-23 17:17:35 -07003651 if (blockList[i]->blockType == kEntryBlock) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003652 dvmCompilerAppendLIR(cUnit,
3653 (LIR *) cUnit->loopAnalysis->branchToBody);
3654 dvmCompilerAppendLIR(cUnit,
3655 (LIR *) cUnit->loopAnalysis->branchToPCR);
3656 }
3657
3658 if (headLIR) {
3659 /*
3660 * Eliminate redundant loads/stores and delay stores into later
3661 * slots
3662 */
3663 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3664 cUnit->lastLIRInsn);
3665 }
3666
3667gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003668 /*
3669 * Check if the block is terminated due to trace length constraint -
3670 * insert an unconditional branch to the chaining cell.
3671 */
3672 if (blockList[i]->needFallThroughBranch) {
3673 genUnconditionalBranch(cUnit,
3674 &labelList[blockList[i]->fallThrough->id]);
3675 }
3676
Ben Chengba4fc8b2009-06-01 13:00:29 -07003677 }
3678
Ben Chenge9695e52009-06-16 16:11:47 -07003679 /* Handle the chaining cells in predefined order */
Ben Chengcec26f62010-01-15 15:29:33 -08003680 for (i = 0; i < kChainingCellGap; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07003681 size_t j;
3682 int *blockIdList = (int *) chainingListByType[i].elemList;
3683
3684 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3685
3686 /* No chaining cells of this type */
3687 if (cUnit->numChainingCells[i] == 0)
3688 continue;
3689
3690 /* Record the first LIR for a new type of chaining cell */
3691 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3692
3693 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3694 int blockId = blockIdList[j];
3695
3696 /* Align this chaining cell first */
Bill Buzbee1465db52009-09-23 17:17:35 -07003697 newLIR0(cUnit, kArmPseudoPseudoAlign4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003698
3699 /* Insert the pseudo chaining instruction */
3700 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3701
3702
3703 switch (blockList[blockId]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003704 case kChainingCellNormal:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003705 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003706 blockList[blockId]->startOffset);
3707 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003708 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07003709 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003710 blockList[blockId]->containingMethod);
3711 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003712 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07003713 handleInvokePredictedChainingCell(cUnit);
3714 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003715 case kChainingCellHot:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003716 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003717 blockList[blockId]->startOffset);
3718 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003719#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07003720 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07003721 handleBackwardBranchChainingCell(cUnit,
3722 blockList[blockId]->startOffset);
3723 break;
3724#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003725 default:
Bill Buzbee1465db52009-09-23 17:17:35 -07003726 LOGE("Bad blocktype %d", blockList[blockId]->blockType);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003727 dvmAbort();
3728 break;
3729 }
3730 }
3731 }
Ben Chenge9695e52009-06-16 16:11:47 -07003732
Ben Chengcec26f62010-01-15 15:29:33 -08003733 /* Mark the bottom of chaining cells */
3734 cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom);
3735
Ben Cheng6c10a972009-10-29 14:39:18 -07003736 /*
3737 * Generate the branch to the dvmJitToInterpNoChain entry point at the end
3738 * of all chaining cells for the overflow cases.
3739 */
3740 if (cUnit->switchOverflowPad) {
3741 loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
3742 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3743 jitToInterpEntries.dvmJitToInterpNoChain), r2);
3744 opRegReg(cUnit, kOpAdd, r1, r1);
3745 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
3746#if defined(EXIT_STATS)
3747 loadConstant(cUnit, r0, kSwitchOverflow);
3748#endif
3749 opReg(cUnit, kOpBlx, r2);
3750 }
3751
Ben Chenge9695e52009-06-16 16:11:47 -07003752 dvmCompilerApplyGlobalOptimizations(cUnit);
jeffhao9e45c0b2010-02-03 10:24:05 -08003753
3754#if defined(WITH_SELF_VERIFICATION)
3755 selfVerificationBranchInsertPass(cUnit);
3756#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003757}
3758
3759/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07003760bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003761{
Ben Chengccd6c012009-10-15 14:52:45 -07003762 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003763
Ben Cheng6999d842010-01-26 16:46:15 -08003764 if (gDvmJit.codeCacheFull) {
Ben Chengccd6c012009-10-15 14:52:45 -07003765 return false;
3766 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003767
Ben Chengccd6c012009-10-15 14:52:45 -07003768 switch (work->kind) {
3769 case kWorkOrderMethod:
3770 res = dvmCompileMethod(work->info, &work->result);
3771 break;
3772 case kWorkOrderTrace:
3773 /* Start compilation with maximally allowed trace length */
3774 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
3775 break;
3776 case kWorkOrderTraceDebug: {
3777 bool oldPrintMe = gDvmJit.printMe;
3778 gDvmJit.printMe = true;
3779 /* Start compilation with maximally allowed trace length */
3780 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
3781 gDvmJit.printMe = oldPrintMe;;
3782 break;
3783 }
3784 default:
3785 res = false;
3786 dvmAbort();
3787 }
3788 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003789}
3790
Ben Chengba4fc8b2009-06-01 13:00:29 -07003791/* Architectural-specific debugging helpers go here */
3792void dvmCompilerArchDump(void)
3793{
3794 /* Print compiled opcode in this VM instance */
3795 int i, start, streak;
3796 char buf[1024];
3797
3798 streak = i = 0;
3799 buf[0] = 0;
3800 while (opcodeCoverage[i] == 0 && i < 256) {
3801 i++;
3802 }
3803 if (i == 256) {
3804 return;
3805 }
3806 for (start = i++, streak = 1; i < 256; i++) {
3807 if (opcodeCoverage[i]) {
3808 streak++;
3809 } else {
3810 if (streak == 1) {
3811 sprintf(buf+strlen(buf), "%x,", start);
3812 } else {
3813 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3814 }
3815 streak = 0;
3816 while (opcodeCoverage[i] == 0 && i < 256) {
3817 i++;
3818 }
3819 if (i < 256) {
3820 streak = 1;
3821 start = i;
3822 }
3823 }
3824 }
3825 if (streak) {
3826 if (streak == 1) {
3827 sprintf(buf+strlen(buf), "%x", start);
3828 } else {
3829 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3830 }
3831 }
3832 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07003833 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003834 }
3835}
Ben Chengd7d426a2009-09-22 11:23:36 -07003836
3837/* Common initialization routine for an architecture family */
3838bool dvmCompilerArchInit()
3839{
3840 int i;
3841
Bill Buzbee1465db52009-09-23 17:17:35 -07003842 for (i = 0; i < kArmLast; i++) {
Ben Chengd7d426a2009-09-22 11:23:36 -07003843 if (EncodingMap[i].opCode != i) {
3844 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
3845 EncodingMap[i].name, i, EncodingMap[i].opCode);
3846 dvmAbort();
3847 }
3848 }
3849
Ben Cheng5d90c202009-11-22 23:31:11 -08003850 return dvmCompilerArchVariantInit();
3851}
3852
3853void *dvmCompilerGetInterpretTemplate()
3854{
3855 return (void*) ((int)gDvmJit.codeCache +
3856 templateEntryOffsets[TEMPLATE_INTERPRET]);
3857}
3858
3859/* Needed by the ld/st optmizatons */
3860ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
3861{
3862 return genRegCopyNoInsert(cUnit, rDest, rSrc);
3863}
3864
3865/* Needed by the register allocator */
3866ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
3867{
3868 return genRegCopy(cUnit, rDest, rSrc);
3869}
3870
3871/* Needed by the register allocator */
3872void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
3873 int srcLo, int srcHi)
3874{
3875 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
3876}
3877
3878void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
3879 int displacement, int rSrc, OpSize size)
3880{
3881 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
3882}
3883
3884void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
3885 int displacement, int rSrcLo, int rSrcHi)
3886{
3887 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
Ben Chengd7d426a2009-09-22 11:23:36 -07003888}