blob: 58c3e794ab27f02a816bf768527b5d4484569f76 [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");
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800615 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700616 }
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);
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800719 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700720 }
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);
Ben Cheng86717f72010-03-05 15:27:21 -0800843#if defined(JIT_STATS)
Bill Buzbee1465db52009-09-23 17:17:35 -0700844 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 Cheng86717f72010-03-05 15:27:21 -08001013#if defined(JIT_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);
Ben Cheng86717f72010-03-05 15:27:21 -08001018#if defined(JIT_STATS)
1019 gDvmJit.invokeMonomorphic++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001020#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);
Ben Cheng86717f72010-03-05 15:27:21 -08001140#if defined(JIT_STATS)
1141 gDvmJit.invokePolymorphic++;
Ben Cheng38329f52009-07-07 14:19:20 -07001142#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
Bill Buzbee45273872010-03-11 11:12:15 -08001229 //If already optimized out, just ignore
1230 if (mir->dalvikInsn.opCode == OP_NOP)
1231 return;
1232
Bill Buzbee1465db52009-09-23 17:17:35 -07001233 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
Bill Buzbeec6f10662010-02-09 11:16:15 -08001234 dvmCompilerFlushAllRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001235
Ben Chengba4fc8b2009-06-01 13:00:29 -07001236 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1237 genPuntToInterp(cUnit, mir->offset);
1238 return;
1239 }
1240 int entryAddr = offsetof(InterpState,
1241 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001242 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001243 /* r0 = dalvik pc */
1244 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1245 /* r1 = dalvik pc of following instruction */
1246 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -07001247 opReg(cUnit, kOpBlx, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001248}
1249
Bill Buzbeec1d9ed42010-02-02 11:04:33 -08001250/*
1251 * To prevent a thread in a monitor wait from blocking the Jit from
1252 * resetting the code cache, heavyweight monitor lock will not
1253 * be allowed to return to an existing translation. Instead, we will
1254 * handle them by branching to a handler, which will in turn call the
1255 * runtime lock routine and then branch directly back to the
1256 * interpreter main loop. Given the high cost of the heavyweight
1257 * lock operation, this additional cost should be slight (especially when
1258 * considering that we expect the vast majority of lock operations to
1259 * use the fast-path thin lock bypass).
1260 */
Ben Cheng5d90c202009-11-22 23:31:11 -08001261static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001262{
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08001263 bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
Bill Buzbee1465db52009-09-23 17:17:35 -07001264 genExportPC(cUnit, mir);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001265 dvmCompilerFlushAllRegs(cUnit); /* Send everything to home location */
1266 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001267 loadValueDirectFixed(cUnit, rlSrc, r1);
1268 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
Bill Buzbeec1d9ed42010-02-02 11:04:33 -08001269 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08001270 if (isEnter) {
Bill Buzbeec1d9ed42010-02-02 11:04:33 -08001271 /* Get dPC of next insn */
1272 loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
1273 dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER)));
1274#if defined(WITH_DEADLOCK_PREDICTION)
1275 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER_DEBUG);
1276#else
1277 genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
1278#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001279 } else {
1280 loadConstant(cUnit, r2, (int)dvmUnlockObject);
Bill Buzbeec1d9ed42010-02-02 11:04:33 -08001281 /* Do the call */
1282 opReg(cUnit, kOpBlx, r2);
Bill Buzbee6bbdd6b2010-02-16 14:40:01 -08001283 opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
1284 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
1285 loadConstant(cUnit, r0,
1286 (int) (cUnit->method->insns + mir->offset +
1287 dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
1288 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1289 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
1290 target->defMask = ENCODE_ALL;
1291 branchOver->generic.target = (LIR *) target;
Elliott Hughes6a555132010-02-25 15:41:42 -08001292 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001293 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001294}
1295
Ben Chengba4fc8b2009-06-01 13:00:29 -07001296/*
1297 * The following are the first-level codegen routines that analyze the format
1298 * of each bytecode then either dispatch special purpose codegen routines
1299 * or produce corresponding Thumb instructions directly.
1300 */
1301
1302static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001303 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001304{
1305 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1306 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1307 return false;
1308}
1309
1310static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1311{
1312 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1313 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
Andy McFadden96516932009-10-28 17:39:02 -07001314 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EB))) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001315 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1316 return true;
1317 }
1318 switch (dalvikOpCode) {
1319 case OP_RETURN_VOID:
1320 genReturnCommon(cUnit,mir);
1321 break;
1322 case OP_UNUSED_73:
1323 case OP_UNUSED_79:
1324 case OP_UNUSED_7A:
1325 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1326 return true;
1327 case OP_NOP:
1328 break;
1329 default:
1330 return true;
1331 }
1332 return false;
1333}
1334
1335static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1336{
Bill Buzbee1465db52009-09-23 17:17:35 -07001337 RegLocation rlDest;
1338 RegLocation rlResult;
1339 if (mir->ssaRep->numDefs == 2) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001340 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001341 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001342 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001343 }
Ben Chenge9695e52009-06-16 16:11:47 -07001344
Ben Chengba4fc8b2009-06-01 13:00:29 -07001345 switch (mir->dalvikInsn.opCode) {
1346 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001347 case OP_CONST_4: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001348 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001349 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1350 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001351 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001352 }
1353 case OP_CONST_WIDE_32: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001354 //TUNING: single routine to load constant pair for support doubles
Bill Buzbee964a7b02010-01-28 12:54:19 -08001355 //TUNING: load 0/-1 separately to avoid load dependency
Bill Buzbeec6f10662010-02-09 11:16:15 -08001356 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001357 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1358 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1359 rlResult.lowReg, 31);
1360 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001361 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001362 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001363 default:
1364 return true;
1365 }
1366 return false;
1367}
1368
1369static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1370{
Bill Buzbee1465db52009-09-23 17:17:35 -07001371 RegLocation rlDest;
1372 RegLocation rlResult;
1373 if (mir->ssaRep->numDefs == 2) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001374 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001375 } else {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001376 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001377 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08001378 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Ben Chenge9695e52009-06-16 16:11:47 -07001379
Ben Chengba4fc8b2009-06-01 13:00:29 -07001380 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001381 case OP_CONST_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001382 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
1383 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001384 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001385 }
1386 case OP_CONST_WIDE_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001387 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1388 0, mir->dalvikInsn.vB << 16);
1389 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001390 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001391 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001392 default:
1393 return true;
1394 }
1395 return false;
1396}
1397
1398static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1399{
1400 /* For OP_THROW_VERIFICATION_ERROR */
1401 genInterpSingleStep(cUnit, mir);
1402 return false;
1403}
1404
1405static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1406{
Bill Buzbee1465db52009-09-23 17:17:35 -07001407 RegLocation rlResult;
1408 RegLocation rlDest;
1409 RegLocation rlSrc;
Ben Chenge9695e52009-06-16 16:11:47 -07001410
Ben Chengba4fc8b2009-06-01 13:00:29 -07001411 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001412 case OP_CONST_STRING_JUMBO:
1413 case OP_CONST_STRING: {
1414 void *strPtr = (void*)
1415 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1416 assert(strPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001417 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1418 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001419 loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
1420 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001421 break;
1422 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001423 case OP_CONST_CLASS: {
1424 void *classPtr = (void*)
1425 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1426 assert(classPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001427 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1428 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001429 loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
1430 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001431 break;
1432 }
1433 case OP_SGET_OBJECT:
1434 case OP_SGET_BOOLEAN:
1435 case OP_SGET_CHAR:
1436 case OP_SGET_BYTE:
1437 case OP_SGET_SHORT:
1438 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001439 int valOffset = offsetof(StaticField, value);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001440 int tReg = dvmCompilerAllocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001441 void *fieldPtr = (void*)
1442 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
1443 assert(fieldPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001444 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1445 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001446 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -08001447#if defined(WITH_SELF_VERIFICATION)
1448 cUnit->heapMemOp = true;
1449#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001450 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
jeffhao9e45c0b2010-02-03 10:24:05 -08001451#if defined(WITH_SELF_VERIFICATION)
1452 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -07001453#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001454 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001455 break;
1456 }
1457 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001458 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001459 void *fieldPtr = (void*)
1460 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001461 int tReg = dvmCompilerAllocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001462 assert(fieldPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001463 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1464 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001465 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -08001466#if defined(WITH_SELF_VERIFICATION)
1467 cUnit->heapMemOp = true;
1468#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001469 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
jeffhao9e45c0b2010-02-03 10:24:05 -08001470#if defined(WITH_SELF_VERIFICATION)
1471 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -07001472#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001473 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001474 break;
1475 }
1476 case OP_SPUT_OBJECT:
1477 case OP_SPUT_BOOLEAN:
1478 case OP_SPUT_CHAR:
1479 case OP_SPUT_BYTE:
1480 case OP_SPUT_SHORT:
1481 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001482 int valOffset = offsetof(StaticField, value);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001483 int tReg = dvmCompilerAllocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001484 void *fieldPtr = (void*)
1485 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001486
Ben Chengba4fc8b2009-06-01 13:00:29 -07001487 assert(fieldPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001488 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001489 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1490 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -08001491#if defined(WITH_SELF_VERIFICATION)
1492 cUnit->heapMemOp = true;
1493#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001494 storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
jeffhao9e45c0b2010-02-03 10:24:05 -08001495#if defined(WITH_SELF_VERIFICATION)
1496 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -07001497#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001498 break;
1499 }
1500 case OP_SPUT_WIDE: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001501 int tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001502 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001503 void *fieldPtr = (void*)
1504 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07001505
Ben Chengba4fc8b2009-06-01 13:00:29 -07001506 assert(fieldPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001507 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001508 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1509 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
jeffhao9e45c0b2010-02-03 10:24:05 -08001510#if defined(WITH_SELF_VERIFICATION)
1511 cUnit->heapMemOp = true;
1512#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001513 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
jeffhao9e45c0b2010-02-03 10:24:05 -08001514#if defined(WITH_SELF_VERIFICATION)
1515 cUnit->heapMemOp = false;
Jeff Hao97319a82009-08-12 16:57:15 -07001516#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001517 break;
1518 }
1519 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001520 /*
1521 * Obey the calling convention and don't mess with the register
1522 * usage.
1523 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001524 ClassObject *classPtr = (void*)
1525 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1526 assert(classPtr != NULL);
1527 assert(classPtr->status & CLASS_INITIALIZED);
Ben Cheng79d173c2009-09-29 16:12:51 -07001528 /*
1529 * If it is going to throw, it should not make to the trace to begin
Bill Buzbee1465db52009-09-23 17:17:35 -07001530 * with. However, Alloc might throw, so we need to genExportPC()
Ben Cheng79d173c2009-09-29 16:12:51 -07001531 */
1532 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001533 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001534 genExportPC(cUnit, mir);
1535 loadConstant(cUnit, r2, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07001536 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001537 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07001538 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -08001539 dvmCompilerClobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07001540 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07001541 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
1542 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07001543 /*
1544 * OOM exception needs to be thrown here and cannot re-execute
1545 */
1546 loadConstant(cUnit, r0,
1547 (int) (cUnit->method->insns + mir->offset));
1548 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
1549 /* noreturn */
1550
Bill Buzbee1465db52009-09-23 17:17:35 -07001551 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07001552 target->defMask = ENCODE_ALL;
1553 branchOver->generic.target = (LIR *) target;
Bill Buzbeec6f10662010-02-09 11:16:15 -08001554 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1555 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001556 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001557 break;
1558 }
1559 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07001560 /*
1561 * Obey the calling convention and don't mess with the register
1562 * usage.
1563 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001564 ClassObject *classPtr =
1565 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
Bill Buzbee4df41a52009-11-12 17:07:16 -08001566 /*
1567 * Note: It is possible that classPtr is NULL at this point,
1568 * even though this instruction has been successfully interpreted.
1569 * If the previous interpretation had a null source, the
1570 * interpreter would not have bothered to resolve the clazz.
1571 * Bail out to the interpreter in this case, and log it
1572 * so that we can tell if it happens frequently.
1573 */
1574 if (classPtr == NULL) {
1575 LOGD("null clazz in OP_CHECK_CAST, single-stepping");
1576 genInterpSingleStep(cUnit, mir);
1577 return false;
1578 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08001579 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001580 loadConstant(cUnit, r1, (int) classPtr );
Bill Buzbeec6f10662010-02-09 11:16:15 -08001581 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001582 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1583 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); /* Null? */
1584 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
1585 /*
1586 * rlSrc.lowReg now contains object->clazz. Note that
1587 * it could have been allocated r0, but we're okay so long
1588 * as we don't do anything desctructive until r0 is loaded
1589 * with clazz.
1590 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001591 /* r0 now contains object->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07001592 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
1593 loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
1594 opRegReg(cUnit, kOpCmp, r0, r1);
1595 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
1596 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -08001597 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001598 /*
1599 * If null, check cast failed - punt to the interpreter. Because
1600 * interpreter will be the one throwing, we don't need to
1601 * genExportPC() here.
1602 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001603 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001604 /* check cast passed - branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07001605 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07001606 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001607 branch1->generic.target = (LIR *)target;
1608 branch2->generic.target = (LIR *)target;
1609 break;
1610 }
1611 default:
1612 return true;
1613 }
1614 return false;
1615}
1616
1617static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
1618{
1619 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001620 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001621 switch (dalvikOpCode) {
1622 case OP_MOVE_EXCEPTION: {
1623 int offset = offsetof(InterpState, self);
1624 int exOffset = offsetof(Thread, exception);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001625 int selfReg = dvmCompilerAllocTemp(cUnit);
1626 int resetReg = dvmCompilerAllocTemp(cUnit);
1627 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1628 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001629 loadWordDisp(cUnit, rGLUE, offset, selfReg);
Bill Buzbeef9f33282009-11-22 12:45:30 -08001630 loadConstant(cUnit, resetReg, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001631 loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
Bill Buzbeef9f33282009-11-22 12:45:30 -08001632 storeWordDisp(cUnit, selfReg, exOffset, resetReg);
Bill Buzbee1465db52009-09-23 17:17:35 -07001633 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001634 break;
1635 }
1636 case OP_MOVE_RESULT:
1637 case OP_MOVE_RESULT_OBJECT: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001638 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001639 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
1640 rlSrc.fp = rlDest.fp;
1641 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001642 break;
1643 }
1644 case OP_MOVE_RESULT_WIDE: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001645 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001646 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
1647 rlSrc.fp = rlDest.fp;
1648 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001649 break;
1650 }
1651 case OP_RETURN_WIDE: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001652 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001653 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
1654 rlDest.fp = rlSrc.fp;
1655 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001656 genReturnCommon(cUnit,mir);
1657 break;
1658 }
1659 case OP_RETURN:
1660 case OP_RETURN_OBJECT: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001661 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001662 RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
1663 rlDest.fp = rlSrc.fp;
1664 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001665 genReturnCommon(cUnit,mir);
1666 break;
1667 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001668 case OP_MONITOR_EXIT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001669 case OP_MONITOR_ENTER:
Bill Buzbeed0937ef2009-12-22 16:15:39 -08001670#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
Ben Cheng5d90c202009-11-22 23:31:11 -08001671 genMonitorPortable(cUnit, mir);
Bill Buzbee1465db52009-09-23 17:17:35 -07001672#else
Ben Cheng5d90c202009-11-22 23:31:11 -08001673 genMonitor(cUnit, mir);
Bill Buzbee1465db52009-09-23 17:17:35 -07001674#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001675 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001676 case OP_THROW: {
1677 genInterpSingleStep(cUnit, mir);
1678 break;
1679 }
1680 default:
1681 return true;
1682 }
1683 return false;
1684}
1685
Bill Buzbeed45ba372009-06-15 17:00:57 -07001686static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
1687{
1688 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001689 RegLocation rlDest;
1690 RegLocation rlSrc;
1691 RegLocation rlResult;
Bill Buzbeed45ba372009-06-15 17:00:57 -07001692
Ben Chengba4fc8b2009-06-01 13:00:29 -07001693 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Ben Cheng5d90c202009-11-22 23:31:11 -08001694 return genArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07001695 }
1696
Bill Buzbee1465db52009-09-23 17:17:35 -07001697 if (mir->ssaRep->numUses == 2)
Bill Buzbeec6f10662010-02-09 11:16:15 -08001698 rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001699 else
Bill Buzbeec6f10662010-02-09 11:16:15 -08001700 rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001701 if (mir->ssaRep->numDefs == 2)
Bill Buzbeec6f10662010-02-09 11:16:15 -08001702 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07001703 else
Bill Buzbeec6f10662010-02-09 11:16:15 -08001704 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Ben Chenge9695e52009-06-16 16:11:47 -07001705
Ben Chengba4fc8b2009-06-01 13:00:29 -07001706 switch (opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001707 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001708 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001709 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001710 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001711 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001712 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001713 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001714 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001715 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001716 case OP_LONG_TO_DOUBLE:
Ben Cheng5d90c202009-11-22 23:31:11 -08001717 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001718 case OP_NEG_INT:
1719 case OP_NOT_INT:
Ben Cheng5d90c202009-11-22 23:31:11 -08001720 return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001721 case OP_NEG_LONG:
1722 case OP_NOT_LONG:
Ben Cheng5d90c202009-11-22 23:31:11 -08001723 return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001724 case OP_NEG_FLOAT:
Ben Cheng5d90c202009-11-22 23:31:11 -08001725 return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001726 case OP_NEG_DOUBLE:
Ben Cheng5d90c202009-11-22 23:31:11 -08001727 return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
Bill Buzbee1465db52009-09-23 17:17:35 -07001728 case OP_MOVE_WIDE:
1729 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001730 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001731 case OP_INT_TO_LONG:
Bill Buzbeec6f10662010-02-09 11:16:15 -08001732 rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
1733 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee964a7b02010-01-28 12:54:19 -08001734 //TUNING: shouldn't loadValueDirect already check for phys reg?
Bill Buzbee1465db52009-09-23 17:17:35 -07001735 if (rlSrc.location == kLocPhysReg) {
1736 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
1737 } else {
1738 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
1739 }
1740 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1741 rlResult.lowReg, 31);
1742 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001743 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001744 case OP_LONG_TO_INT:
Bill Buzbeec6f10662010-02-09 11:16:15 -08001745 rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
1746 rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
Bill Buzbee1465db52009-09-23 17:17:35 -07001747 // Intentional fallthrough
Ben Chengba4fc8b2009-06-01 13:00:29 -07001748 case OP_MOVE:
1749 case OP_MOVE_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001750 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001751 break;
1752 case OP_INT_TO_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07001753 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001754 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001755 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
1756 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001757 break;
1758 case OP_INT_TO_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001759 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001760 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001761 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
1762 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001763 break;
1764 case OP_INT_TO_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001765 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001766 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001767 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
1768 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001769 break;
1770 case OP_ARRAY_LENGTH: {
1771 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07001772 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1773 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
1774 mir->offset, NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001775 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001776 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
1777 rlResult.lowReg);
1778 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001779 break;
1780 }
1781 default:
1782 return true;
1783 }
1784 return false;
1785}
1786
1787static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
1788{
1789 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001790 RegLocation rlDest;
1791 RegLocation rlResult;
1792 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001793 if (dalvikOpCode == OP_CONST_WIDE_16) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001794 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
1795 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001796 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
Bill Buzbee964a7b02010-01-28 12:54:19 -08001797 //TUNING: do high separately to avoid load dependency
Bill Buzbee1465db52009-09-23 17:17:35 -07001798 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1799 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001800 } else if (dalvikOpCode == OP_CONST_16) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08001801 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
1802 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001803 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
1804 storeValue(cUnit, rlDest, rlResult);
1805 } else
Ben Chengba4fc8b2009-06-01 13:00:29 -07001806 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001807 return false;
1808}
1809
1810/* Compare agaist zero */
1811static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001812 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001813{
1814 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001815 ArmConditionCode cond;
Bill Buzbeec6f10662010-02-09 11:16:15 -08001816 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001817 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1818 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001819
Bill Buzbee270c1d62009-08-13 16:58:07 -07001820//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07001821 switch (dalvikOpCode) {
1822 case OP_IF_EQZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001823 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001824 break;
1825 case OP_IF_NEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001826 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001827 break;
1828 case OP_IF_LTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001829 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001830 break;
1831 case OP_IF_GEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001832 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001833 break;
1834 case OP_IF_GTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001835 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001836 break;
1837 case OP_IF_LEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07001838 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001839 break;
1840 default:
1841 cond = 0;
1842 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
Bill Buzbeefc519dc2010-03-06 23:30:57 -08001843 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001844 }
1845 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1846 /* This mostly likely will be optimized away in a later phase */
1847 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1848 return false;
1849}
1850
Elliott Hughesb4c05972010-02-24 16:36:18 -08001851static bool isPowerOfTwo(int x)
1852{
1853 return (x & (x - 1)) == 0;
1854}
1855
1856// Returns true if no more than two bits are set in 'x'.
1857static bool isPopCountLE2(unsigned int x)
1858{
1859 x &= x - 1;
1860 return (x & (x - 1)) == 0;
1861}
1862
1863// Returns the index of the lowest set bit in 'x'.
1864static int lowestSetBit(unsigned int x) {
1865 int bit_posn = 0;
1866 while ((x & 0xf) == 0) {
1867 bit_posn += 4;
1868 x >>= 4;
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001869 }
Elliott Hughesb4c05972010-02-24 16:36:18 -08001870 while ((x & 1) == 0) {
1871 bit_posn++;
1872 x >>= 1;
1873 }
1874 return bit_posn;
1875}
1876
1877// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1878// and store the result in 'rlDest'.
1879static bool handleEasyMultiply(CompilationUnit *cUnit,
1880 RegLocation rlSrc, RegLocation rlDest, int lit)
1881{
1882 // Can we simplify this multiplication?
1883 bool powerOfTwo = false;
1884 bool popCountLE2 = false;
1885 bool powerOfTwoMinusOne = false;
1886 if (lit < 2) {
1887 // Avoid special cases.
1888 return false;
1889 } else if (isPowerOfTwo(lit)) {
1890 powerOfTwo = true;
1891 } else if (isPopCountLE2(lit)) {
1892 popCountLE2 = true;
1893 } else if (isPowerOfTwo(lit + 1)) {
1894 powerOfTwoMinusOne = true;
1895 } else {
1896 return false;
1897 }
1898 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1899 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
1900 if (powerOfTwo) {
1901 // Shift.
1902 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1903 lowestSetBit(lit));
1904 } else if (popCountLE2) {
1905 // Shift and add and shift.
1906 int firstBit = lowestSetBit(lit);
1907 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1908 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1909 firstBit, secondBit);
1910 } else {
1911 // Reverse subtract: (src << (shift + 1)) - src.
1912 assert(powerOfTwoMinusOne);
1913 // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1914 int tReg = dvmCompilerAllocTemp(cUnit);
1915 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1916 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1917 }
1918 storeValue(cUnit, rlDest, rlResult);
1919 return true;
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001920}
1921
Ben Chengba4fc8b2009-06-01 13:00:29 -07001922static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
1923{
1924 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbeec6f10662010-02-09 11:16:15 -08001925 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
1926 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07001927 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001928 int lit = mir->dalvikInsn.vC;
Ben Cheng4f489172009-09-27 17:08:35 -07001929 OpKind op = 0; /* Make gcc happy */
Bill Buzbee1465db52009-09-23 17:17:35 -07001930 int shiftOp = false;
1931 bool isDiv = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001932
Ben Chengba4fc8b2009-06-01 13:00:29 -07001933 int __aeabi_idivmod(int op1, int op2);
1934 int __aeabi_idiv(int op1, int op2);
1935
1936 switch (dalvikOpCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001937 case OP_RSUB_INT_LIT8:
1938 case OP_RSUB_INT: {
1939 int tReg;
1940 //TUNING: add support for use of Arm rsub op
1941 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001942 tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07001943 loadConstant(cUnit, tReg, lit);
Bill Buzbeec6f10662010-02-09 11:16:15 -08001944 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07001945 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1946 tReg, rlSrc.lowReg);
1947 storeValue(cUnit, rlDest, rlResult);
1948 return false;
1949 break;
1950 }
1951
Ben Chengba4fc8b2009-06-01 13:00:29 -07001952 case OP_ADD_INT_LIT8:
1953 case OP_ADD_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07001954 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001955 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001956 case OP_MUL_INT_LIT8:
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001957 case OP_MUL_INT_LIT16: {
Elliott Hughesb4c05972010-02-24 16:36:18 -08001958 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1959 return false;
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001960 }
Elliott Hughesb4c05972010-02-24 16:36:18 -08001961 op = kOpMul;
Bill Buzbee1465db52009-09-23 17:17:35 -07001962 break;
Bill Buzbee78cb0e22010-02-11 14:04:53 -08001963 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001964 case OP_AND_INT_LIT8:
1965 case OP_AND_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07001966 op = kOpAnd;
1967 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001968 case OP_OR_INT_LIT8:
1969 case OP_OR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07001970 op = kOpOr;
1971 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001972 case OP_XOR_INT_LIT8:
1973 case OP_XOR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07001974 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001975 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001976 case OP_SHL_INT_LIT8:
Bill Buzbee0e605272009-12-01 14:28:05 -08001977 lit &= 31;
Bill Buzbee1465db52009-09-23 17:17:35 -07001978 shiftOp = true;
1979 op = kOpLsl;
1980 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001981 case OP_SHR_INT_LIT8:
Bill Buzbee0e605272009-12-01 14:28:05 -08001982 lit &= 31;
Bill Buzbee1465db52009-09-23 17:17:35 -07001983 shiftOp = true;
1984 op = kOpAsr;
1985 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001986 case OP_USHR_INT_LIT8:
Bill Buzbee0e605272009-12-01 14:28:05 -08001987 lit &= 31;
Bill Buzbee1465db52009-09-23 17:17:35 -07001988 shiftOp = true;
1989 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001990 break;
1991
1992 case OP_DIV_INT_LIT8:
1993 case OP_DIV_INT_LIT16:
Ben Chengba4fc8b2009-06-01 13:00:29 -07001994 case OP_REM_INT_LIT8:
1995 case OP_REM_INT_LIT16:
1996 if (lit == 0) {
1997 /* Let the interpreter deal with div by 0 */
1998 genInterpSingleStep(cUnit, mir);
1999 return false;
2000 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08002001 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002002 loadValueDirectFixed(cUnit, rlSrc, r0);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002003 dvmCompilerClobber(cUnit, r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002004 if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2005 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2006 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2007 isDiv = true;
2008 } else {
2009 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2010 isDiv = false;
2011 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002012 loadConstant(cUnit, r1, lit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002013 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -08002014 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002015 if (isDiv)
Bill Buzbeec6f10662010-02-09 11:16:15 -08002016 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002017 else
Bill Buzbeec6f10662010-02-09 11:16:15 -08002018 rlResult = dvmCompilerGetReturnAlt(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002019 storeValue(cUnit, rlDest, rlResult);
2020 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002021 break;
2022 default:
2023 return true;
2024 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002025 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002026 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07002027 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2028 if (shiftOp && (lit == 0)) {
2029 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2030 } else {
2031 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2032 }
2033 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002034 return false;
2035}
2036
2037static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2038{
2039 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2040 int fieldOffset;
2041
2042 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2043 InstField *pInstField = (InstField *)
2044 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002045
2046 assert(pInstField != NULL);
2047 fieldOffset = pInstField->byteOffset;
2048 } else {
Ben Chenga0e7b602009-10-13 23:09:01 -07002049 /* Deliberately break the code while make the compiler happy */
2050 fieldOffset = -1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002051 }
2052 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002053 case OP_NEW_ARRAY: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002054 // Generates a call - use explicit registers
Bill Buzbeec6f10662010-02-09 11:16:15 -08002055 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2056 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002057 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002058 void *classPtr = (void*)
2059 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2060 assert(classPtr != NULL);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002061 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002062 genExportPC(cUnit, mir);
2063 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002064 loadConstant(cUnit, r0, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07002065 loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
Ben Cheng4f489172009-09-27 17:08:35 -07002066 /*
2067 * "len < 0": bail to the interpreter to re-execute the
2068 * instruction
2069 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002070 ArmLIR *pcrLabel =
Bill Buzbee1465db52009-09-23 17:17:35 -07002071 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002072 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07002073 opReg(cUnit, kOpBlx, r3);
Elliott Hughes6a555132010-02-25 15:41:42 -08002074 dvmCompilerClobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07002075 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07002076 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2077 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07002078 /*
2079 * OOM exception needs to be thrown here and cannot re-execute
2080 */
2081 loadConstant(cUnit, r0,
2082 (int) (cUnit->method->insns + mir->offset));
2083 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2084 /* noreturn */
2085
Bill Buzbee1465db52009-09-23 17:17:35 -07002086 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07002087 target->defMask = ENCODE_ALL;
2088 branchOver->generic.target = (LIR *) target;
Bill Buzbeec6f10662010-02-09 11:16:15 -08002089 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002090 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002091 break;
2092 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002093 case OP_INSTANCE_OF: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002094 // May generate a call - use explicit registers
Bill Buzbeec6f10662010-02-09 11:16:15 -08002095 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2096 RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002097 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002098 ClassObject *classPtr =
2099 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
Bill Buzbee480e6782010-01-27 15:43:08 -08002100 /*
2101 * Note: It is possible that classPtr is NULL at this point,
2102 * even though this instruction has been successfully interpreted.
2103 * If the previous interpretation had a null source, the
2104 * interpreter would not have bothered to resolve the clazz.
2105 * Bail out to the interpreter in this case, and log it
2106 * so that we can tell if it happens frequently.
2107 */
2108 if (classPtr == NULL) {
2109 LOGD("null clazz in OP_INSTANCE_OF, single-stepping");
2110 genInterpSingleStep(cUnit, mir);
2111 break;
2112 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08002113 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002114 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002115 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002116//TUNING: compare to 0 primative to allow use of CB[N]Z
Bill Buzbee1465db52009-09-23 17:17:35 -07002117 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002118 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee1465db52009-09-23 17:17:35 -07002119 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002120 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002121 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002122 /* r1 now contains object->clazz */
2123 loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002124 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee1465db52009-09-23 17:17:35 -07002125 opRegReg(cUnit, kOpCmp, r1, r2);
2126 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2127 genRegCopy(cUnit, r0, r1);
2128 genRegCopy(cUnit, r1, r2);
2129 opReg(cUnit, kOpBlx, r3);
Elliott Hughes6a555132010-02-25 15:41:42 -08002130 dvmCompilerClobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002131 /* branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07002132 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07002133 target->defMask = ENCODE_ALL;
Bill Buzbeec6f10662010-02-09 11:16:15 -08002134 rlResult = dvmCompilerGetReturn(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002135 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002136 branch1->generic.target = (LIR *)target;
2137 branch2->generic.target = (LIR *)target;
2138 break;
2139 }
2140 case OP_IGET_WIDE:
2141 genIGetWide(cUnit, mir, fieldOffset);
2142 break;
2143 case OP_IGET:
2144 case OP_IGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002145 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002146 break;
2147 case OP_IGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07002148 genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002149 break;
2150 case OP_IGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002151 genIGet(cUnit, mir, kSignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002152 break;
2153 case OP_IGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002154 genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002155 break;
2156 case OP_IGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002157 genIGet(cUnit, mir, kSignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002158 break;
2159 case OP_IPUT_WIDE:
2160 genIPutWide(cUnit, mir, fieldOffset);
2161 break;
2162 case OP_IPUT:
2163 case OP_IPUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002164 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002165 break;
2166 case OP_IPUT_SHORT:
2167 case OP_IPUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002168 genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002169 break;
2170 case OP_IPUT_BYTE:
2171 case OP_IPUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07002172 genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002173 break;
2174 default:
2175 return true;
2176 }
2177 return false;
2178}
2179
2180static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2181{
2182 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2183 int fieldOffset = mir->dalvikInsn.vC;
2184 switch (dalvikOpCode) {
2185 case OP_IGET_QUICK:
2186 case OP_IGET_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07002187 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002188 break;
2189 case OP_IPUT_QUICK:
2190 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07002191 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002192 break;
2193 case OP_IGET_WIDE_QUICK:
2194 genIGetWide(cUnit, mir, fieldOffset);
2195 break;
2196 case OP_IPUT_WIDE_QUICK:
2197 genIPutWide(cUnit, mir, fieldOffset);
2198 break;
2199 default:
2200 return true;
2201 }
2202 return false;
2203
2204}
2205
2206/* Compare agaist zero */
2207static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002208 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002209{
2210 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002211 ArmConditionCode cond;
Bill Buzbeec6f10662010-02-09 11:16:15 -08002212 RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2213 RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002214
Bill Buzbee1465db52009-09-23 17:17:35 -07002215 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
2216 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
2217 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002218
2219 switch (dalvikOpCode) {
2220 case OP_IF_EQ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002221 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002222 break;
2223 case OP_IF_NE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002224 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002225 break;
2226 case OP_IF_LT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002227 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002228 break;
2229 case OP_IF_GE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002230 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002231 break;
2232 case OP_IF_GT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002233 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002234 break;
2235 case OP_IF_LE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002236 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002237 break;
2238 default:
2239 cond = 0;
2240 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
Bill Buzbeefc519dc2010-03-06 23:30:57 -08002241 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002242 }
2243 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2244 /* This mostly likely will be optimized away in a later phase */
2245 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2246 return false;
2247}
2248
2249static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2250{
2251 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002252
2253 switch (opCode) {
2254 case OP_MOVE_16:
2255 case OP_MOVE_OBJECT_16:
2256 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002257 case OP_MOVE_OBJECT_FROM16: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002258 storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
2259 dvmCompilerGetSrc(cUnit, mir, 0));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002260 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002261 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002262 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002263 case OP_MOVE_WIDE_FROM16: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002264 storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
2265 dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002266 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002267 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002268 default:
2269 return true;
2270 }
2271 return false;
2272}
2273
2274static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2275{
2276 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002277 RegLocation rlSrc1;
2278 RegLocation rlSrc2;
2279 RegLocation rlDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002280
2281 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
Ben Cheng5d90c202009-11-22 23:31:11 -08002282 return genArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002283 }
2284
Bill Buzbee1465db52009-09-23 17:17:35 -07002285 /* APUTs have 3 sources and no targets */
2286 if (mir->ssaRep->numDefs == 0) {
2287 if (mir->ssaRep->numUses == 3) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002288 rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
2289 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
2290 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
Bill Buzbee1465db52009-09-23 17:17:35 -07002291 } else {
2292 assert(mir->ssaRep->numUses == 4);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002293 rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2294 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
2295 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
Bill Buzbee1465db52009-09-23 17:17:35 -07002296 }
2297 } else {
2298 /* Two sources and 1 dest. Deduce the operand sizes */
2299 if (mir->ssaRep->numUses == 4) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002300 rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
2301 rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
Bill Buzbee1465db52009-09-23 17:17:35 -07002302 } else {
2303 assert(mir->ssaRep->numUses == 2);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002304 rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
2305 rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002306 }
2307 if (mir->ssaRep->numDefs == 2) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002308 rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002309 } else {
2310 assert(mir->ssaRep->numDefs == 1);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002311 rlDest = dvmCompilerGetDest(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002312 }
2313 }
2314
2315
Ben Chengba4fc8b2009-06-01 13:00:29 -07002316 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002317 case OP_CMPL_FLOAT:
2318 case OP_CMPG_FLOAT:
2319 case OP_CMPL_DOUBLE:
2320 case OP_CMPG_DOUBLE:
Ben Cheng5d90c202009-11-22 23:31:11 -08002321 return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002322 case OP_CMP_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07002323 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002324 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002325 case OP_AGET_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002326 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002327 break;
2328 case OP_AGET:
2329 case OP_AGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002330 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002331 break;
2332 case OP_AGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07002333 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002334 break;
2335 case OP_AGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002336 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002337 break;
2338 case OP_AGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002339 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002340 break;
2341 case OP_AGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002342 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002343 break;
2344 case OP_APUT_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002345 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002346 break;
2347 case OP_APUT:
2348 case OP_APUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002349 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002350 break;
2351 case OP_APUT_SHORT:
2352 case OP_APUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002353 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002354 break;
2355 case OP_APUT_BYTE:
2356 case OP_APUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07002357 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002358 break;
2359 default:
2360 return true;
2361 }
2362 return false;
2363}
2364
Ben Cheng6c10a972009-10-29 14:39:18 -07002365/*
2366 * Find the matching case.
2367 *
2368 * return values:
2369 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
2370 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
2371 * r1 (high 32-bit): the branch offset of the matching case (only for indexes
2372 * above MAX_CHAINED_SWITCH_CASES).
2373 *
2374 * Instructions around the call are:
2375 *
2376 * mov r2, pc
2377 * blx &findPackedSwitchIndex
2378 * mov pc, r0
2379 * .align4
2380 * chaining cell for case 0 [8 bytes]
2381 * chaining cell for case 1 [8 bytes]
2382 * :
2383 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
2384 * chaining cell for case default [8 bytes]
2385 * noChain exit
2386 */
2387s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
2388{
2389 int size;
2390 int firstKey;
2391 const int *entries;
2392 int index;
2393 int jumpIndex;
2394 int caseDPCOffset = 0;
2395 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
2396 int chainingPC = (pc + 4) & ~3;
2397
2398 /*
2399 * Packed switch data format:
2400 * ushort ident = 0x0100 magic value
2401 * ushort size number of entries in the table
2402 * int first_key first (and lowest) switch case value
2403 * int targets[size] branch targets, relative to switch opcode
2404 *
2405 * Total size is (4+size*2) 16-bit code units.
2406 */
2407 size = switchData[1];
2408 assert(size > 0);
2409
2410 firstKey = switchData[2];
2411 firstKey |= switchData[3] << 16;
2412
2413
2414 /* The entries are guaranteed to be aligned on a 32-bit boundary;
2415 * we can treat them as a native int array.
2416 */
2417 entries = (const int*) &switchData[4];
2418 assert(((u4)entries & 0x3) == 0);
2419
2420 index = testVal - firstKey;
2421
2422 /* Jump to the default cell */
2423 if (index < 0 || index >= size) {
2424 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
2425 /* Jump to the non-chaining exit point */
2426 } else if (index >= MAX_CHAINED_SWITCH_CASES) {
2427 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
2428 caseDPCOffset = entries[index];
2429 /* Jump to the inline chaining cell */
2430 } else {
2431 jumpIndex = index;
2432 }
2433
2434 chainingPC += jumpIndex * 8;
2435 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
2436}
2437
2438/* See comments for findPackedSwitchIndex */
2439s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
2440{
2441 int size;
2442 const int *keys;
2443 const int *entries;
2444 int chainingPC = (pc + 4) & ~3;
2445 int i;
2446
2447 /*
2448 * Sparse switch data format:
2449 * ushort ident = 0x0200 magic value
2450 * ushort size number of entries in the table; > 0
2451 * int keys[size] keys, sorted low-to-high; 32-bit aligned
2452 * int targets[size] branch targets, relative to switch opcode
2453 *
2454 * Total size is (2+size*4) 16-bit code units.
2455 */
2456
2457 size = switchData[1];
2458 assert(size > 0);
2459
2460 /* The keys are guaranteed to be aligned on a 32-bit boundary;
2461 * we can treat them as a native int array.
2462 */
2463 keys = (const int*) &switchData[2];
2464 assert(((u4)keys & 0x3) == 0);
2465
2466 /* The entries are guaranteed to be aligned on a 32-bit boundary;
2467 * we can treat them as a native int array.
2468 */
2469 entries = keys + size;
2470 assert(((u4)entries & 0x3) == 0);
2471
2472 /*
2473 * Run through the list of keys, which are guaranteed to
2474 * be sorted low-to-high.
2475 *
2476 * Most tables have 3-4 entries. Few have more than 10. A binary
2477 * search here is probably not useful.
2478 */
2479 for (i = 0; i < size; i++) {
2480 int k = keys[i];
2481 if (k == testVal) {
2482 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
2483 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
2484 i : MAX_CHAINED_SWITCH_CASES + 1;
2485 chainingPC += jumpIndex * 8;
2486 return (((s8) entries[i]) << 32) | (u8) chainingPC;
2487 } else if (k > testVal) {
2488 break;
2489 }
2490 }
2491 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
2492}
2493
Ben Chengba4fc8b2009-06-01 13:00:29 -07002494static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2495{
2496 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2497 switch (dalvikOpCode) {
2498 case OP_FILL_ARRAY_DATA: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002499 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002500 // Making a call - use explicit registers
Bill Buzbeec6f10662010-02-09 11:16:15 -08002501 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002502 genExportPC(cUnit, mir);
2503 loadValueDirectFixed(cUnit, rlSrc, r0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002504 loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData);
Ben Cheng6c10a972009-10-29 14:39:18 -07002505 loadConstant(cUnit, r1,
2506 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
Bill Buzbee1465db52009-09-23 17:17:35 -07002507 opReg(cUnit, kOpBlx, r2);
Elliott Hughes6a555132010-02-25 15:41:42 -08002508 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002509 /* generate a branch over if successful */
2510 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2511 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
2512 loadConstant(cUnit, r0,
2513 (int) (cUnit->method->insns + mir->offset));
2514 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2515 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2516 target->defMask = ENCODE_ALL;
2517 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002518 break;
2519 }
2520 /*
Ben Cheng6c10a972009-10-29 14:39:18 -07002521 * Compute the goto target of up to
2522 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
2523 * See the comment before findPackedSwitchIndex for the code layout.
Ben Chengba4fc8b2009-06-01 13:00:29 -07002524 */
2525 case OP_PACKED_SWITCH:
2526 case OP_SPARSE_SWITCH: {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002527 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
2528 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002529 loadValueDirectFixed(cUnit, rlSrc, r1);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002530 dvmCompilerLockAllTemps(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07002531 const u2 *switchData =
2532 cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
2533 u2 size = switchData[1];
2534
Ben Chengba4fc8b2009-06-01 13:00:29 -07002535 if (dalvikOpCode == OP_PACKED_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -07002536 loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002537 } else {
Ben Cheng6c10a972009-10-29 14:39:18 -07002538 loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002539 }
Ben Cheng6c10a972009-10-29 14:39:18 -07002540 /* r0 <- Addr of the switch data */
2541 loadConstant(cUnit, r0,
2542 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
2543 /* r2 <- pc of the instruction following the blx */
2544 opRegReg(cUnit, kOpMov, r2, rpc);
Bill Buzbee1465db52009-09-23 17:17:35 -07002545 opReg(cUnit, kOpBlx, r4PC);
Elliott Hughes6a555132010-02-25 15:41:42 -08002546 dvmCompilerClobberCallRegs(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07002547 /* pc <- computed goto target */
2548 opRegReg(cUnit, kOpMov, rpc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002549 break;
2550 }
2551 default:
2552 return true;
2553 }
2554 return false;
2555}
2556
2557static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002558 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002559{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07002560 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002561 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002562
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07002563 if (bb->fallThrough != NULL)
2564 retChainingCell = &labelList[bb->fallThrough->id];
2565
Ben Chengba4fc8b2009-06-01 13:00:29 -07002566 DecodedInstruction *dInsn = &mir->dalvikInsn;
2567 switch (mir->dalvikInsn.opCode) {
2568 /*
2569 * calleeMethod = this->clazz->vtable[
2570 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2571 * ]
2572 */
2573 case OP_INVOKE_VIRTUAL:
2574 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002575 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002576 int methodIndex =
2577 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2578 methodIndex;
2579
2580 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2581 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2582 else
2583 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2584
Ben Cheng38329f52009-07-07 14:19:20 -07002585 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2586 retChainingCell,
2587 predChainingCell,
2588 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002589 break;
2590 }
2591 /*
2592 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2593 * ->pResMethods[BBBB]->methodIndex]
2594 */
2595 /* TODO - not excersized in RunPerf.jar */
2596 case OP_INVOKE_SUPER:
2597 case OP_INVOKE_SUPER_RANGE: {
2598 int mIndex = cUnit->method->clazz->pDvmDex->
2599 pResMethods[dInsn->vB]->methodIndex;
2600 const Method *calleeMethod =
2601 cUnit->method->clazz->super->vtable[mIndex];
2602
2603 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2604 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2605 else
2606 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2607
2608 /* r0 = calleeMethod */
2609 loadConstant(cUnit, r0, (int) calleeMethod);
2610
Ben Cheng38329f52009-07-07 14:19:20 -07002611 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2612 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002613 break;
2614 }
2615 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2616 case OP_INVOKE_DIRECT:
2617 case OP_INVOKE_DIRECT_RANGE: {
2618 const Method *calleeMethod =
2619 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2620
2621 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2622 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2623 else
2624 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2625
2626 /* r0 = calleeMethod */
2627 loadConstant(cUnit, r0, (int) calleeMethod);
2628
Ben Cheng38329f52009-07-07 14:19:20 -07002629 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2630 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002631 break;
2632 }
2633 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2634 case OP_INVOKE_STATIC:
2635 case OP_INVOKE_STATIC_RANGE: {
2636 const Method *calleeMethod =
2637 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2638
2639 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2640 genProcessArgsNoRange(cUnit, mir, dInsn,
2641 NULL /* no null check */);
2642 else
2643 genProcessArgsRange(cUnit, mir, dInsn,
2644 NULL /* no null check */);
2645
2646 /* r0 = calleeMethod */
2647 loadConstant(cUnit, r0, (int) calleeMethod);
2648
Ben Cheng38329f52009-07-07 14:19:20 -07002649 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2650 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002651 break;
2652 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002653 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -07002654 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2655 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07002656 *
2657 * Given "invoke-interface {v0}", the following is the generated code:
2658 *
2659 * 0x426a9abe : ldr r0, [r5, #0] --+
2660 * 0x426a9ac0 : mov r7, r5 |
2661 * 0x426a9ac2 : sub r7, #24 |
2662 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2663 * 0x426a9ac6 : beq 0x426a9afe |
2664 * 0x426a9ac8 : stmia r7, <r0> --+
2665 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2666 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
2667 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
2668 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
2669 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
2670 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
2671 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
Ben Chenga8e64a72009-10-20 13:01:36 -07002672 * 0x426a9ad8 : mov r8, r1 --+
2673 * 0x426a9ada : mov r9, r2 |
2674 * 0x426a9adc : mov r10, r3 |
Ben Cheng38329f52009-07-07 14:19:20 -07002675 * 0x426a9ade : mov r0, r3 |
2676 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
2677 * 0x426a9ae2 : ldr r2, [pc, #76] |
2678 * 0x426a9ae4 : ldr r3, [pc, #68] |
2679 * 0x426a9ae6 : ldr r7, [pc, #64] |
2680 * 0x426a9ae8 : blx r7 --+
Ben Chenga8e64a72009-10-20 13:01:36 -07002681 * 0x426a9aea : mov r1, r8 --> r1 <- rechain count
Ben Cheng38329f52009-07-07 14:19:20 -07002682 * 0x426a9aec : cmp r1, #0 --> compare against 0
2683 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
2684 * 0x426a9af0 : ldr r7, [r6, #96] --+
Ben Chenga8e64a72009-10-20 13:01:36 -07002685 * 0x426a9af2 : mov r2, r9 | dvmJitToPatchPredictedChain
2686 * 0x426a9af4 : mov r3, r10 |
Ben Cheng38329f52009-07-07 14:19:20 -07002687 * 0x426a9af6 : blx r7 --+
2688 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
2689 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2690 * 0x426a9afc : blx_2 see above --+
2691 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
2692 * 0x426a9afe (0042): ldr r0, [pc, #52]
2693 * Exception_Handling:
2694 * 0x426a9b00 (0044): ldr r1, [r6, #84]
2695 * 0x426a9b02 (0046): blx r1
2696 * 0x426a9b04 (0048): .align4
2697 * -------- chaining cell (hot): 0x0021
2698 * 0x426a9b04 (0048): ldr r0, [r6, #92]
2699 * 0x426a9b06 (004a): blx r0
2700 * 0x426a9b08 (004c): data 0x7872(30834)
2701 * 0x426a9b0a (004e): data 0x428b(17035)
2702 * 0x426a9b0c (0050): .align4
2703 * -------- chaining cell (predicted)
2704 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
2705 * 0x426a9b0e (0052): data 0x0000(0)
2706 * 0x426a9b10 (0054): data 0x0000(0) --> class
2707 * 0x426a9b12 (0056): data 0x0000(0)
2708 * 0x426a9b14 (0058): data 0x0000(0) --> method
2709 * 0x426a9b16 (005a): data 0x0000(0)
2710 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
2711 * 0x426a9b1a (005e): data 0x0000(0)
2712 * 0x426a9b28 (006c): .word (0xad0392a5)
2713 * 0x426a9b2c (0070): .word (0x6e750)
2714 * 0x426a9b30 (0074): .word (0x4109a618)
2715 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002716 */
2717 case OP_INVOKE_INTERFACE:
2718 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002719 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002720 int methodIndex = dInsn->vB;
2721
Bill Buzbee1465db52009-09-23 17:17:35 -07002722 /* Ensure that nothing is both live and dirty */
Bill Buzbeec6f10662010-02-09 11:16:15 -08002723 dvmCompilerFlushAllRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002724
Ben Chengba4fc8b2009-06-01 13:00:29 -07002725 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
2726 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2727 else
2728 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2729
Ben Cheng38329f52009-07-07 14:19:20 -07002730 /* "this" is already left in r0 by genProcessArgs* */
2731
2732 /* r4PC = dalvikCallsite */
2733 loadConstant(cUnit, r4PC,
2734 (int) (cUnit->method->insns + mir->offset));
2735
2736 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002737 ArmLIR *addrRetChain =
Bill Buzbee1465db52009-09-23 17:17:35 -07002738 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002739 addrRetChain->generic.target = (LIR *) retChainingCell;
2740
2741 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002742 ArmLIR *predictedChainingCell =
Bill Buzbee1465db52009-09-23 17:17:35 -07002743 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002744 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2745
2746 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2747
2748 /* return through lr - jump to the chaining cell */
2749 genUnconditionalBranch(cUnit, predChainingCell);
2750
2751 /*
2752 * null-check on "this" may have been eliminated, but we still need
2753 * a PC-reconstruction label for stack overflow bailout.
2754 */
2755 if (pcrLabel == NULL) {
2756 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002757 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07002758 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07002759 pcrLabel->operands[0] = dPC;
2760 pcrLabel->operands[1] = mir->offset;
2761 /* Insert the place holder to the growable list */
2762 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2763 }
2764
2765 /* return through lr+2 - punt to the interpreter */
2766 genUnconditionalBranch(cUnit, pcrLabel);
2767
2768 /*
2769 * return through lr+4 - fully resolve the callee method.
2770 * r1 <- count
2771 * r2 <- &predictedChainCell
2772 * r3 <- this->class
2773 * r4 <- dPC
2774 * r7 <- this->class->vtable
2775 */
2776
2777 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee1465db52009-09-23 17:17:35 -07002778 genRegCopy(cUnit, r8, r1);
2779 genRegCopy(cUnit, r9, r2);
2780 genRegCopy(cUnit, r10, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002781
Ben Chengba4fc8b2009-06-01 13:00:29 -07002782 /* r0 now contains this->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07002783 genRegCopy(cUnit, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002784
2785 /* r1 = BBBB */
2786 loadConstant(cUnit, r1, dInsn->vB);
2787
2788 /* r2 = method (caller) */
2789 loadConstant(cUnit, r2, (int) cUnit->method);
2790
2791 /* r3 = pDvmDex */
2792 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
2793
2794 loadConstant(cUnit, r7,
2795 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee1465db52009-09-23 17:17:35 -07002796 opReg(cUnit, kOpBlx, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002797
2798 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
2799
Bill Buzbee1465db52009-09-23 17:17:35 -07002800 genRegCopy(cUnit, r1, r8);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002801
Ben Cheng38329f52009-07-07 14:19:20 -07002802 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07002803 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002804
Bill Buzbee1465db52009-09-23 17:17:35 -07002805 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07002806
Bill Buzbee270c1d62009-08-13 16:58:07 -07002807 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2808 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002809
Bill Buzbee1465db52009-09-23 17:17:35 -07002810 genRegCopy(cUnit, r2, r9);
2811 genRegCopy(cUnit, r3, r10);
Ben Cheng38329f52009-07-07 14:19:20 -07002812
2813 /*
2814 * r0 = calleeMethod
2815 * r2 = &predictedChainingCell
2816 * r3 = class
2817 *
2818 * &returnChainingCell has been loaded into r1 but is not needed
2819 * when patching the chaining cell and will be clobbered upon
2820 * returning so it will be reconstructed again.
2821 */
Bill Buzbee1465db52009-09-23 17:17:35 -07002822 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002823
2824 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002825 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002826 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07002827
2828 bypassRechaining->generic.target = (LIR *) addrRetChain;
2829
Ben Chengba4fc8b2009-06-01 13:00:29 -07002830 /*
2831 * r0 = this, r1 = calleeMethod,
2832 * r1 = &ChainingCell,
2833 * r4PC = callsiteDPC,
2834 */
2835 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
Ben Cheng86717f72010-03-05 15:27:21 -08002836#if defined(JIT_STATS)
2837 gDvmJit.invokePolymorphic++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002838#endif
2839 /* Handle exceptions using the interpreter */
2840 genTrap(cUnit, mir->offset, pcrLabel);
2841 break;
2842 }
2843 /* NOP */
2844 case OP_INVOKE_DIRECT_EMPTY: {
2845 return false;
2846 }
2847 case OP_FILLED_NEW_ARRAY:
2848 case OP_FILLED_NEW_ARRAY_RANGE: {
2849 /* Just let the interpreter deal with these */
2850 genInterpSingleStep(cUnit, mir);
2851 break;
2852 }
2853 default:
2854 return true;
2855 }
2856 return false;
2857}
2858
2859static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002860 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002861{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002862 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
2863 ArmLIR *predChainingCell = &labelList[bb->taken->id];
2864 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002865
2866 DecodedInstruction *dInsn = &mir->dalvikInsn;
2867 switch (mir->dalvikInsn.opCode) {
2868 /* calleeMethod = this->clazz->vtable[BBBB] */
2869 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
2870 case OP_INVOKE_VIRTUAL_QUICK: {
2871 int methodIndex = dInsn->vB;
2872 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
2873 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2874 else
2875 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2876
Ben Cheng38329f52009-07-07 14:19:20 -07002877 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2878 retChainingCell,
2879 predChainingCell,
2880 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002881 break;
2882 }
2883 /* calleeMethod = method->clazz->super->vtable[BBBB] */
2884 case OP_INVOKE_SUPER_QUICK:
2885 case OP_INVOKE_SUPER_QUICK_RANGE: {
2886 const Method *calleeMethod =
2887 cUnit->method->clazz->super->vtable[dInsn->vB];
2888
2889 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
2890 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2891 else
2892 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2893
2894 /* r0 = calleeMethod */
2895 loadConstant(cUnit, r0, (int) calleeMethod);
2896
Ben Cheng38329f52009-07-07 14:19:20 -07002897 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2898 calleeMethod);
2899 /* Handle exceptions using the interpreter */
2900 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002901 break;
2902 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002903 default:
2904 return true;
2905 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002906 return false;
2907}
2908
2909/*
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002910 * This operation is complex enough that we'll do it partly inline
2911 * and partly with a handler. NOTE: the handler uses hardcoded
2912 * values for string object offsets and must be revisitied if the
2913 * layout changes.
2914 */
2915static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
2916{
2917#if defined(USE_GLOBAL_STRING_DEFS)
2918 return false;
2919#else
2920 ArmLIR *rollback;
Bill Buzbeec6f10662010-02-09 11:16:15 -08002921 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
2922 RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002923
2924 loadValueDirectFixed(cUnit, rlThis, r0);
2925 loadValueDirectFixed(cUnit, rlComp, r1);
2926 /* Test objects for NULL */
2927 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
2928 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
2929 /*
2930 * TUNING: we could check for object pointer equality before invoking
2931 * handler. Unclear whether the gain would be worth the added code size
2932 * expansion.
2933 */
2934 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002935 storeValue(cUnit, inlinedTarget(cUnit, mir, false),
2936 dvmCompilerGetReturn(cUnit));
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002937 return true;
2938#endif
2939}
2940
2941static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
2942{
2943#if defined(USE_GLOBAL_STRING_DEFS)
2944 return false;
2945#else
Bill Buzbeec6f10662010-02-09 11:16:15 -08002946 RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
2947 RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002948
2949 loadValueDirectFixed(cUnit, rlThis, r0);
2950 loadValueDirectFixed(cUnit, rlChar, r1);
2951 if (!singleI) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08002952 RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002953 loadValueDirectFixed(cUnit, rlStart, r2);
2954 } else {
2955 loadConstant(cUnit, r2, 0);
2956 }
2957 /* Test objects for NULL */
2958 genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
2959 genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
Bill Buzbeec6f10662010-02-09 11:16:15 -08002960 storeValue(cUnit, inlinedTarget(cUnit, mir, false),
2961 dvmCompilerGetReturn(cUnit));
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002962 return true;
2963#endif
2964}
2965
Bill Buzbee1f748632010-03-02 16:14:41 -08002966static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
2967{
2968 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
2969 RegLocation rlDest = inlinedTarget(cUnit, mir, false);
2970 rlObj = loadValue(cUnit, rlObj, kCoreReg);
2971 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
2972 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
2973 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
2974 rlResult.lowReg);
2975 storeValue(cUnit, rlDest, rlResult);
2976 return false;
2977}
2978
2979static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
2980{
2981 int contents = offsetof(ArrayObject, contents);
2982 RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
2983 RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1);
2984 RegLocation rlDest = inlinedTarget(cUnit, mir, false);
2985 RegLocation rlResult;
2986 rlObj = loadValue(cUnit, rlObj, kCoreReg);
2987 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
2988 int regMax = dvmCompilerAllocTemp(cUnit);
2989 int regOff = dvmCompilerAllocTemp(cUnit);
2990 int regPtr = dvmCompilerAllocTemp(cUnit);
2991 ArmLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
2992 mir->offset, NULL);
2993 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
2994 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
2995 loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
2996 genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
2997 dvmCompilerFreeTemp(cUnit, regMax);
2998 opRegImm(cUnit, kOpAdd, regPtr, contents);
2999 opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
3000 rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3001 loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
3002 storeValue(cUnit, rlDest, rlResult);
3003 return false;
3004}
3005
3006static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
3007{
3008 RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
3009 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
3010 RegLocation rlDest = inlinedTarget(cUnit, mir, false);;
3011 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3012 int signReg = dvmCompilerAllocTemp(cUnit);
3013 /*
3014 * abs(x) = y<=x>>31, (x+y)^y.
3015 * Thumb2's IT block also yields 3 instructions, but imposes
3016 * scheduling constraints.
3017 */
3018 opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
3019 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3020 opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3021 storeValue(cUnit, rlDest, rlResult);
3022 return false;
3023}
3024
3025static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
3026{
3027 RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
3028 RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
3029 rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
3030 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
3031 int signReg = dvmCompilerAllocTemp(cUnit);
3032 /*
3033 * abs(x) = y<=x>>31, (x+y)^y.
3034 * Thumb2 IT block allows slightly shorter sequence,
3035 * but introduces a scheduling barrier. Stick with this
3036 * mechanism for now.
3037 */
3038 opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
3039 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
3040 opRegRegReg(cUnit, kOpAdc, rlResult.highReg, rlSrc.highReg, signReg);
3041 opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
3042 opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
3043 storeValueWide(cUnit, rlDest, rlResult);
3044 return false;
3045}
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003046
3047/*
Bill Buzbeece46c942009-11-20 15:41:34 -08003048 * NOTE: Handles both range and non-range versions (arguments
3049 * have already been normalized by this point).
Ben Chengba4fc8b2009-06-01 13:00:29 -07003050 */
Bill Buzbeece46c942009-11-20 15:41:34 -08003051static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003052{
3053 DecodedInstruction *dInsn = &mir->dalvikInsn;
3054 switch( mir->dalvikInsn.opCode) {
Bill Buzbeece46c942009-11-20 15:41:34 -08003055 case OP_EXECUTE_INLINE_RANGE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003056 case OP_EXECUTE_INLINE: {
3057 unsigned int i;
3058 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003059 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003060 int operation = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07003061 int tReg1;
3062 int tReg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003063 switch (operation) {
3064 case INLINE_EMPTYINLINEMETHOD:
3065 return false; /* Nop */
3066 case INLINE_STRING_LENGTH:
3067 return genInlinedStringLength(cUnit, mir);
3068 case INLINE_MATH_ABS_INT:
3069 return genInlinedAbsInt(cUnit, mir);
3070 case INLINE_MATH_ABS_LONG:
3071 return genInlinedAbsLong(cUnit, mir);
3072 case INLINE_MATH_MIN_INT:
3073 return genInlinedMinMaxInt(cUnit, mir, true);
3074 case INLINE_MATH_MAX_INT:
3075 return genInlinedMinMaxInt(cUnit, mir, false);
3076 case INLINE_STRING_CHARAT:
3077 return genInlinedStringCharAt(cUnit, mir);
3078 case INLINE_MATH_SQRT:
3079 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003080 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003081 else
3082 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003083 case INLINE_MATH_ABS_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003084 if (genInlinedAbsFloat(cUnit, mir))
3085 return false;
3086 else
3087 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003088 case INLINE_MATH_ABS_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003089 if (genInlinedAbsDouble(cUnit, mir))
3090 return false;
3091 else
3092 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003093 case INLINE_STRING_COMPARETO:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003094 if (genInlinedCompareTo(cUnit, mir))
3095 return false;
3096 else
3097 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003098 case INLINE_STRING_INDEXOF_I:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003099 if (genInlinedIndexOf(cUnit, mir, true /* I */))
3100 return false;
3101 else
3102 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003103 case INLINE_STRING_INDEXOF_II:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003104 if (genInlinedIndexOf(cUnit, mir, false /* I */))
3105 return false;
3106 else
3107 break;
3108 case INLINE_STRING_EQUALS:
3109 case INLINE_MATH_COS:
3110 case INLINE_MATH_SIN:
3111 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003112 default:
Bill Buzbeefc519dc2010-03-06 23:30:57 -08003113 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003114 }
Bill Buzbeec6f10662010-02-09 11:16:15 -08003115 dvmCompilerFlushAllRegs(cUnit); /* Everything to home location */
Elliott Hughes6a555132010-02-25 15:41:42 -08003116 dvmCompilerClobberCallRegs(cUnit);
Bill Buzbeec6f10662010-02-09 11:16:15 -08003117 dvmCompilerClobber(cUnit, r4PC);
3118 dvmCompilerClobber(cUnit, r7);
Bill Buzbee1465db52009-09-23 17:17:35 -07003119 opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3120 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003121 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
Bill Buzbee1465db52009-09-23 17:17:35 -07003122 genExportPC(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003123 for (i=0; i < dInsn->vA; i++) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003124 loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003125 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003126 opReg(cUnit, kOpBlx, r4PC);
3127 opRegImm(cUnit, kOpAdd, r13, 8);
Bill Buzbeece46c942009-11-20 15:41:34 -08003128 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3129 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3130 loadConstant(cUnit, r0,
3131 (int) (cUnit->method->insns + mir->offset));
3132 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3133 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3134 target->defMask = ENCODE_ALL;
3135 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003136 break;
3137 }
3138 default:
3139 return true;
3140 }
3141 return false;
3142}
3143
3144static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3145{
Bill Buzbee1465db52009-09-23 17:17:35 -07003146 //TUNING: We're using core regs here - not optimal when target is a double
Bill Buzbeec6f10662010-02-09 11:16:15 -08003147 RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
3148 RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003149 loadConstantValue(cUnit, rlResult.lowReg,
3150 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3151 loadConstantValue(cUnit, rlResult.highReg,
3152 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3153 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003154 return false;
3155}
3156
Ben Chengba4fc8b2009-06-01 13:00:29 -07003157/*
3158 * The following are special processing routines that handle transfer of
3159 * controls between compiled code and the interpreter. Certain VM states like
3160 * Dalvik PC and special-purpose registers are reconstructed here.
3161 */
3162
Ben Cheng1efc9c52009-06-08 18:25:27 -07003163/* Chaining cell for code that may need warmup. */
3164static void handleNormalChainingCell(CompilationUnit *cUnit,
3165 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003166{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003167 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3168 jitToInterpEntries.dvmJitToInterpNormal), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003169 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003170 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3171}
3172
3173/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003174 * Chaining cell for instructions that immediately following already translated
3175 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003176 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003177static void handleHotChainingCell(CompilationUnit *cUnit,
3178 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003179{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003180 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
Ben Cheng40094c12010-02-24 20:58:44 -08003181 jitToInterpEntries.dvmJitToInterpTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003182 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003183 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3184}
3185
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003186#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003187/* Chaining cell for branches that branch back into the same basic block */
3188static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3189 unsigned int offset)
3190{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003191#if defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07003192 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Ben Cheng40094c12010-02-24 20:58:44 -08003193 offsetof(InterpState,
3194 jitToInterpEntries.dvmJitToInterpBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003195#else
Bill Buzbee1465db52009-09-23 17:17:35 -07003196 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003197 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3198#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07003199 newLIR1(cUnit, kThumbBlxR, r0);
Jeff Hao97319a82009-08-12 16:57:15 -07003200 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3201}
3202
3203#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003204/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003205static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3206 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003207{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003208 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
Ben Cheng40094c12010-02-24 20:58:44 -08003209 jitToInterpEntries.dvmJitToInterpTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003210 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003211 addWordData(cUnit, (int) (callee->insns), true);
3212}
3213
Ben Cheng38329f52009-07-07 14:19:20 -07003214/* Chaining cell for monomorphic method invocations. */
3215static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3216{
3217
3218 /* Should not be executed in the initial state */
3219 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3220 /* To be filled: class */
3221 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3222 /* To be filled: method */
3223 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3224 /*
3225 * Rechain count. The initial value of 0 here will trigger chaining upon
3226 * the first invocation of this callsite.
3227 */
3228 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3229}
3230
Ben Chengba4fc8b2009-06-01 13:00:29 -07003231/* Load the Dalvik PC into r0 and jump to the specified target */
3232static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003233 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003234{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003235 ArmLIR **pcrLabel =
3236 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003237 int numElems = cUnit->pcReconstructionList.numUsed;
3238 int i;
3239 for (i = 0; i < numElems; i++) {
3240 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3241 /* r0 = dalvik PC */
3242 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3243 genUnconditionalBranch(cUnit, targetLabel);
3244 }
3245}
3246
Bill Buzbee1465db52009-09-23 17:17:35 -07003247static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
3248 "kMirOpPhi",
3249 "kMirOpNullNRangeUpCheck",
3250 "kMirOpNullNRangeDownCheck",
3251 "kMirOpLowerBound",
3252 "kMirOpPunt",
Ben Cheng4238ec22009-08-24 16:32:22 -07003253};
3254
3255/*
3256 * vA = arrayReg;
3257 * vB = idxReg;
3258 * vC = endConditionReg;
3259 * arg[0] = maxC
3260 * arg[1] = minC
3261 * arg[2] = loopBranchConditionCode
3262 */
3263static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3264{
Bill Buzbee1465db52009-09-23 17:17:35 -07003265 /*
3266 * NOTE: these synthesized blocks don't have ssa names assigned
3267 * for Dalvik registers. However, because they dominate the following
3268 * blocks we can simply use the Dalvik name w/ subscript 0 as the
3269 * ssa name.
3270 */
Ben Cheng4238ec22009-08-24 16:32:22 -07003271 DecodedInstruction *dInsn = &mir->dalvikInsn;
3272 const int lenOffset = offsetof(ArrayObject, length);
Ben Cheng4238ec22009-08-24 16:32:22 -07003273 const int maxC = dInsn->arg[0];
3274 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07003275 int regLength;
3276 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3277 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
Ben Cheng4238ec22009-08-24 16:32:22 -07003278
3279 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07003280 rlArray = loadValue(cUnit, rlArray, kCoreReg);
3281 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
3282 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003283 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3284
3285 /* regLength <- len(arrayRef) */
Bill Buzbeec6f10662010-02-09 11:16:15 -08003286 regLength = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003287 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07003288
3289 int delta = maxC;
3290 /*
3291 * If the loop end condition is ">=" instead of ">", then the largest value
3292 * of the index is "endCondition - 1".
3293 */
3294 if (dInsn->arg[2] == OP_IF_GE) {
3295 delta--;
3296 }
3297
3298 if (delta) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003299 int tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003300 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
3301 rlIdxEnd.lowReg = tReg;
Bill Buzbeec6f10662010-02-09 11:16:15 -08003302 dvmCompilerFreeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003303 }
3304 /* Punt if "regIdxEnd < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003305 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07003306 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003307}
3308
3309/*
3310 * vA = arrayReg;
3311 * vB = idxReg;
3312 * vC = endConditionReg;
3313 * arg[0] = maxC
3314 * arg[1] = minC
3315 * arg[2] = loopBranchConditionCode
3316 */
3317static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3318{
3319 DecodedInstruction *dInsn = &mir->dalvikInsn;
3320 const int lenOffset = offsetof(ArrayObject, length);
Bill Buzbeec6f10662010-02-09 11:16:15 -08003321 const int regLength = dvmCompilerAllocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07003322 const int maxC = dInsn->arg[0];
3323 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07003324 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3325 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
Ben Cheng4238ec22009-08-24 16:32:22 -07003326
3327 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07003328 rlArray = loadValue(cUnit, rlArray, kCoreReg);
3329 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
3330 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003331 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3332
3333 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07003334 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07003335
3336 if (maxC) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003337 int tReg = dvmCompilerAllocTemp(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003338 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
3339 rlIdxInit.lowReg = tReg;
Bill Buzbeec6f10662010-02-09 11:16:15 -08003340 dvmCompilerFreeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003341 }
3342
3343 /* Punt if "regIdxInit < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003344 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07003345 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003346}
3347
3348/*
3349 * vA = idxReg;
3350 * vB = minC;
3351 */
3352static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3353{
3354 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -07003355 const int minC = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07003356 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
Ben Cheng4238ec22009-08-24 16:32:22 -07003357
3358 /* regIdx <- initial index value */
Bill Buzbee1465db52009-09-23 17:17:35 -07003359 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003360
3361 /* Punt if "regIdxInit + minC >= 0" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003362 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003363 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3364}
3365
3366/* Extended MIR instructions like PHI */
3367static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3368{
Bill Buzbee1465db52009-09-23 17:17:35 -07003369 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
Ben Cheng4238ec22009-08-24 16:32:22 -07003370 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3371 false);
3372 strcpy(msg, extendedMIROpNames[opOffset]);
Bill Buzbee1465db52009-09-23 17:17:35 -07003373 newLIR1(cUnit, kArmPseudoExtended, (int) msg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003374
3375 switch (mir->dalvikInsn.opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003376 case kMirOpPhi: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003377 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07003378 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07003379 break;
3380 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003381 case kMirOpNullNRangeUpCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003382 genHoistedChecksForCountUpLoop(cUnit, mir);
3383 break;
3384 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003385 case kMirOpNullNRangeDownCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003386 genHoistedChecksForCountDownLoop(cUnit, mir);
3387 break;
3388 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003389 case kMirOpLowerBound: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003390 genHoistedLowerBoundCheck(cUnit, mir);
3391 break;
3392 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003393 case kMirOpPunt: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003394 genUnconditionalBranch(cUnit,
3395 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3396 break;
3397 }
3398 default:
3399 break;
3400 }
3401}
3402
3403/*
3404 * Create a PC-reconstruction cell for the starting offset of this trace.
3405 * Since the PCR cell is placed near the end of the compiled code which is
3406 * usually out of range for a conditional branch, we put two branches (one
3407 * branch over to the loop body and one layover branch to the actual PCR) at the
3408 * end of the entry block.
3409 */
3410static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3411 ArmLIR *bodyLabel)
3412{
3413 /* Set up the place holder to reconstruct this Dalvik PC */
3414 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003415 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng4238ec22009-08-24 16:32:22 -07003416 pcrLabel->operands[0] =
3417 (int) (cUnit->method->insns + entry->startOffset);
3418 pcrLabel->operands[1] = entry->startOffset;
3419 /* Insert the place holder to the growable list */
3420 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3421
3422 /*
3423 * Next, create two branches - one branch over to the loop body and the
3424 * other branch to the PCR cell to punt.
3425 */
3426 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003427 branchToBody->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07003428 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003429 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07003430 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3431
3432 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003433 branchToPCR->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07003434 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003435 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003436 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3437}
3438
Ben Chengba4fc8b2009-06-01 13:00:29 -07003439void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3440{
3441 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003442 ArmLIR *labelList =
3443 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengcec26f62010-01-15 15:29:33 -08003444 GrowableList chainingListByType[kChainingCellGap];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003445 int i;
3446
3447 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003448 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003449 */
Ben Chengcec26f62010-01-15 15:29:33 -08003450 for (i = 0; i < kChainingCellGap; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07003451 dvmInitGrowableList(&chainingListByType[i], 2);
3452 }
3453
3454 BasicBlock **blockList = cUnit->blockList;
3455
Bill Buzbee6e963e12009-06-17 16:56:19 -07003456 if (cUnit->executionCount) {
3457 /*
3458 * Reserve 6 bytes at the beginning of the trace
3459 * +----------------------------+
3460 * | execution count (4 bytes) |
3461 * +----------------------------+
3462 * | chain cell offset (2 bytes)|
3463 * +----------------------------+
3464 * ...and then code to increment the execution
3465 * count:
3466 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3467 * sub r0, #10 @ back up to addr of executionCount
3468 * ldr r1, [r0]
3469 * add r1, #1
3470 * str r1, [r0]
3471 */
Bill Buzbee1465db52009-09-23 17:17:35 -07003472 newLIR1(cUnit, kArm16BitData, 0);
3473 newLIR1(cUnit, kArm16BitData, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003474 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07003475 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003476 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003477 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee1465db52009-09-23 17:17:35 -07003478 newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
3479 newLIR2(cUnit, kThumbSubRI8, r0, 10);
3480 newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
3481 newLIR2(cUnit, kThumbAddRI8, r1, 1);
3482 newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003483 } else {
3484 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003485 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07003486 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003487 cUnit->headerSize = 2;
3488 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003489
Ben Chengba4fc8b2009-06-01 13:00:29 -07003490 /* Handle the content in each basic block */
3491 for (i = 0; i < cUnit->numBlocks; i++) {
3492 blockList[i]->visited = true;
3493 MIR *mir;
3494
3495 labelList[i].operands[0] = blockList[i]->startOffset;
3496
Ben Chengcec26f62010-01-15 15:29:33 -08003497 if (blockList[i]->blockType >= kChainingCellGap) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07003498 /*
3499 * Append the label pseudo LIR first. Chaining cells will be handled
3500 * separately afterwards.
3501 */
3502 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3503 }
3504
Bill Buzbee1465db52009-09-23 17:17:35 -07003505 if (blockList[i]->blockType == kEntryBlock) {
3506 labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07003507 if (blockList[i]->firstMIRInsn == NULL) {
3508 continue;
3509 } else {
3510 setupLoopEntryBlock(cUnit, blockList[i],
3511 &labelList[blockList[i]->fallThrough->id]);
3512 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003513 } else if (blockList[i]->blockType == kExitBlock) {
3514 labelList[i].opCode = ARM_PSEUDO_kExitBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07003515 goto gen_fallthrough;
Bill Buzbee1465db52009-09-23 17:17:35 -07003516 } else if (blockList[i]->blockType == kDalvikByteCode) {
3517 labelList[i].opCode = kArmPseudoNormalBlockLabel;
Ben Chenge9695e52009-06-16 16:11:47 -07003518 /* Reset the register state */
Bill Buzbeec6f10662010-02-09 11:16:15 -08003519 dvmCompilerResetRegPool(cUnit);
3520 dvmCompilerClobberAllRegs(cUnit);
3521 dvmCompilerResetNullCheck(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003522 } else {
3523 switch (blockList[i]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003524 case kChainingCellNormal:
3525 labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003526 /* handle the codegen later */
3527 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003528 &chainingListByType[kChainingCellNormal], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003529 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003530 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07003531 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003532 ARM_PSEUDO_kChainingCellInvokeSingleton;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003533 labelList[i].operands[0] =
3534 (int) blockList[i]->containingMethod;
3535 /* handle the codegen later */
3536 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003537 &chainingListByType[kChainingCellInvokeSingleton],
Ben Cheng38329f52009-07-07 14:19:20 -07003538 (void *) i);
3539 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003540 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07003541 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003542 ARM_PSEUDO_kChainingCellInvokePredicted;
Ben Cheng38329f52009-07-07 14:19:20 -07003543 /* handle the codegen later */
3544 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003545 &chainingListByType[kChainingCellInvokePredicted],
Ben Cheng38329f52009-07-07 14:19:20 -07003546 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003547 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003548 case kChainingCellHot:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003549 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003550 ARM_PSEUDO_kChainingCellHot;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003551 /* handle the codegen later */
3552 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003553 &chainingListByType[kChainingCellHot],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003554 (void *) i);
3555 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003556 case kPCReconstruction:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003557 /* Make sure exception handling block is next */
3558 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003559 ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003560 assert (i == cUnit->numBlocks - 2);
3561 handlePCReconstruction(cUnit, &labelList[i+1]);
3562 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003563 case kExceptionHandling:
3564 labelList[i].opCode = kArmPseudoEHBlockLabel;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003565 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003566 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3567 jitToInterpEntries.dvmJitToInterpPunt),
3568 r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07003569 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003570 }
3571 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003572#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07003573 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07003574 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07003575 ARM_PSEUDO_kChainingCellBackwardBranch;
Jeff Hao97319a82009-08-12 16:57:15 -07003576 /* handle the codegen later */
3577 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07003578 &chainingListByType[kChainingCellBackwardBranch],
Jeff Hao97319a82009-08-12 16:57:15 -07003579 (void *) i);
3580 break;
3581#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003582 default:
3583 break;
3584 }
3585 continue;
3586 }
Ben Chenge9695e52009-06-16 16:11:47 -07003587
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003588 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003589
Ben Chengba4fc8b2009-06-01 13:00:29 -07003590 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003591
Bill Buzbeec6f10662010-02-09 11:16:15 -08003592 dvmCompilerResetRegPool(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003593 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003594 dvmCompilerClobberAllRegs(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003595 }
3596
3597 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
Bill Buzbeec6f10662010-02-09 11:16:15 -08003598 dvmCompilerResetDefTracking(cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07003599 }
3600
3601 if (mir->dalvikInsn.opCode >= kMirOpFirst) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003602 handleExtendedMIR(cUnit, mir);
3603 continue;
3604 }
3605
Bill Buzbee1465db52009-09-23 17:17:35 -07003606
Ben Chengba4fc8b2009-06-01 13:00:29 -07003607 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3608 InstructionFormat dalvikFormat =
3609 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003610 ArmLIR *boundaryLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07003611 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
Ben Chengccd6c012009-10-15 14:52:45 -07003612 mir->offset,
3613 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
3614 );
Ben Cheng4238ec22009-08-24 16:32:22 -07003615 if (mir->ssaRep) {
3616 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07003617 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07003618 }
3619
Ben Chenge9695e52009-06-16 16:11:47 -07003620 /* Remember the first LIR for this block */
3621 if (headLIR == NULL) {
3622 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07003623 /* Set the first boundaryLIR as a scheduling barrier */
3624 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07003625 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003626
Ben Chengba4fc8b2009-06-01 13:00:29 -07003627 bool notHandled;
3628 /*
3629 * Debugging: screen the opcode first to see if it is in the
3630 * do[-not]-compile list
3631 */
3632 bool singleStepMe =
3633 gDvmJit.includeSelectedOp !=
3634 ((gDvmJit.opList[dalvikOpCode >> 3] &
3635 (1 << (dalvikOpCode & 0x7))) !=
3636 0);
3637 if (singleStepMe || cUnit->allSingleStep) {
3638 notHandled = false;
3639 genInterpSingleStep(cUnit, mir);
3640 } else {
3641 opcodeCoverage[dalvikOpCode]++;
3642 switch (dalvikFormat) {
3643 case kFmt10t:
3644 case kFmt20t:
3645 case kFmt30t:
3646 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3647 mir, blockList[i], labelList);
3648 break;
3649 case kFmt10x:
3650 notHandled = handleFmt10x(cUnit, mir);
3651 break;
3652 case kFmt11n:
3653 case kFmt31i:
3654 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3655 break;
3656 case kFmt11x:
3657 notHandled = handleFmt11x(cUnit, mir);
3658 break;
3659 case kFmt12x:
3660 notHandled = handleFmt12x(cUnit, mir);
3661 break;
3662 case kFmt20bc:
3663 notHandled = handleFmt20bc(cUnit, mir);
3664 break;
3665 case kFmt21c:
3666 case kFmt31c:
3667 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3668 break;
3669 case kFmt21h:
3670 notHandled = handleFmt21h(cUnit, mir);
3671 break;
3672 case kFmt21s:
3673 notHandled = handleFmt21s(cUnit, mir);
3674 break;
3675 case kFmt21t:
3676 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3677 labelList);
3678 break;
3679 case kFmt22b:
3680 case kFmt22s:
3681 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3682 break;
3683 case kFmt22c:
3684 notHandled = handleFmt22c(cUnit, mir);
3685 break;
3686 case kFmt22cs:
3687 notHandled = handleFmt22cs(cUnit, mir);
3688 break;
3689 case kFmt22t:
3690 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3691 labelList);
3692 break;
3693 case kFmt22x:
3694 case kFmt32x:
3695 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3696 break;
3697 case kFmt23x:
3698 notHandled = handleFmt23x(cUnit, mir);
3699 break;
3700 case kFmt31t:
3701 notHandled = handleFmt31t(cUnit, mir);
3702 break;
3703 case kFmt3rc:
3704 case kFmt35c:
3705 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3706 labelList);
3707 break;
3708 case kFmt3rms:
3709 case kFmt35ms:
3710 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3711 labelList);
3712 break;
3713 case kFmt3inline:
Andy McFaddenb0a05412009-11-19 10:23:41 -08003714 case kFmt3rinline:
Bill Buzbeece46c942009-11-20 15:41:34 -08003715 notHandled = handleExecuteInline(cUnit, mir);
Andy McFaddenb0a05412009-11-19 10:23:41 -08003716 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003717 case kFmt51l:
3718 notHandled = handleFmt51l(cUnit, mir);
3719 break;
3720 default:
3721 notHandled = true;
3722 break;
3723 }
3724 }
3725 if (notHandled) {
3726 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3727 mir->offset,
3728 dalvikOpCode, getOpcodeName(dalvikOpCode),
3729 dalvikFormat);
Bill Buzbeefc519dc2010-03-06 23:30:57 -08003730 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003731 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003732 }
3733 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003734
Bill Buzbee1465db52009-09-23 17:17:35 -07003735 if (blockList[i]->blockType == kEntryBlock) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003736 dvmCompilerAppendLIR(cUnit,
3737 (LIR *) cUnit->loopAnalysis->branchToBody);
3738 dvmCompilerAppendLIR(cUnit,
3739 (LIR *) cUnit->loopAnalysis->branchToPCR);
3740 }
3741
3742 if (headLIR) {
3743 /*
3744 * Eliminate redundant loads/stores and delay stores into later
3745 * slots
3746 */
3747 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3748 cUnit->lastLIRInsn);
3749 }
3750
3751gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003752 /*
3753 * Check if the block is terminated due to trace length constraint -
3754 * insert an unconditional branch to the chaining cell.
3755 */
3756 if (blockList[i]->needFallThroughBranch) {
3757 genUnconditionalBranch(cUnit,
3758 &labelList[blockList[i]->fallThrough->id]);
3759 }
3760
Ben Chengba4fc8b2009-06-01 13:00:29 -07003761 }
3762
Ben Chenge9695e52009-06-16 16:11:47 -07003763 /* Handle the chaining cells in predefined order */
Ben Chengcec26f62010-01-15 15:29:33 -08003764 for (i = 0; i < kChainingCellGap; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07003765 size_t j;
3766 int *blockIdList = (int *) chainingListByType[i].elemList;
3767
3768 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3769
3770 /* No chaining cells of this type */
3771 if (cUnit->numChainingCells[i] == 0)
3772 continue;
3773
3774 /* Record the first LIR for a new type of chaining cell */
3775 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3776
3777 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3778 int blockId = blockIdList[j];
3779
3780 /* Align this chaining cell first */
Bill Buzbee1465db52009-09-23 17:17:35 -07003781 newLIR0(cUnit, kArmPseudoPseudoAlign4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003782
3783 /* Insert the pseudo chaining instruction */
3784 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3785
3786
3787 switch (blockList[blockId]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003788 case kChainingCellNormal:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003789 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003790 blockList[blockId]->startOffset);
3791 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003792 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07003793 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003794 blockList[blockId]->containingMethod);
3795 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003796 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07003797 handleInvokePredictedChainingCell(cUnit);
3798 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07003799 case kChainingCellHot:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003800 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003801 blockList[blockId]->startOffset);
3802 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003803#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07003804 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07003805 handleBackwardBranchChainingCell(cUnit,
3806 blockList[blockId]->startOffset);
3807 break;
3808#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003809 default:
Bill Buzbee1465db52009-09-23 17:17:35 -07003810 LOGE("Bad blocktype %d", blockList[blockId]->blockType);
Bill Buzbeefc519dc2010-03-06 23:30:57 -08003811 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003812 }
3813 }
3814 }
Ben Chenge9695e52009-06-16 16:11:47 -07003815
Ben Chengcec26f62010-01-15 15:29:33 -08003816 /* Mark the bottom of chaining cells */
3817 cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kArmChainingCellBottom);
3818
Ben Cheng6c10a972009-10-29 14:39:18 -07003819 /*
3820 * Generate the branch to the dvmJitToInterpNoChain entry point at the end
3821 * of all chaining cells for the overflow cases.
3822 */
3823 if (cUnit->switchOverflowPad) {
3824 loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
3825 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3826 jitToInterpEntries.dvmJitToInterpNoChain), r2);
3827 opRegReg(cUnit, kOpAdd, r1, r1);
3828 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
Ben Cheng86717f72010-03-05 15:27:21 -08003829#if defined(JIT_STATS)
Ben Cheng6c10a972009-10-29 14:39:18 -07003830 loadConstant(cUnit, r0, kSwitchOverflow);
3831#endif
3832 opReg(cUnit, kOpBlx, r2);
3833 }
3834
Ben Chenge9695e52009-06-16 16:11:47 -07003835 dvmCompilerApplyGlobalOptimizations(cUnit);
jeffhao9e45c0b2010-02-03 10:24:05 -08003836
3837#if defined(WITH_SELF_VERIFICATION)
3838 selfVerificationBranchInsertPass(cUnit);
3839#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003840}
3841
3842/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07003843bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003844{
Ben Chengccd6c012009-10-15 14:52:45 -07003845 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003846
Ben Cheng6999d842010-01-26 16:46:15 -08003847 if (gDvmJit.codeCacheFull) {
Ben Chengccd6c012009-10-15 14:52:45 -07003848 return false;
3849 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003850
Ben Chengccd6c012009-10-15 14:52:45 -07003851 switch (work->kind) {
3852 case kWorkOrderMethod:
3853 res = dvmCompileMethod(work->info, &work->result);
3854 break;
3855 case kWorkOrderTrace:
3856 /* Start compilation with maximally allowed trace length */
Bill Buzbeefc519dc2010-03-06 23:30:57 -08003857 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
3858 work->bailPtr);
Ben Chengccd6c012009-10-15 14:52:45 -07003859 break;
3860 case kWorkOrderTraceDebug: {
3861 bool oldPrintMe = gDvmJit.printMe;
3862 gDvmJit.printMe = true;
3863 /* Start compilation with maximally allowed trace length */
Bill Buzbeefc519dc2010-03-06 23:30:57 -08003864 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
3865 work->bailPtr);
Ben Chengccd6c012009-10-15 14:52:45 -07003866 gDvmJit.printMe = oldPrintMe;;
3867 break;
3868 }
3869 default:
3870 res = false;
Bill Buzbeefc519dc2010-03-06 23:30:57 -08003871 LOGE("Jit: unknown work order type");
3872 assert(0); // Bail if debug build, discard oteherwise
Ben Chengccd6c012009-10-15 14:52:45 -07003873 }
3874 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003875}
3876
Ben Chengba4fc8b2009-06-01 13:00:29 -07003877/* Architectural-specific debugging helpers go here */
3878void dvmCompilerArchDump(void)
3879{
3880 /* Print compiled opcode in this VM instance */
3881 int i, start, streak;
3882 char buf[1024];
3883
3884 streak = i = 0;
3885 buf[0] = 0;
3886 while (opcodeCoverage[i] == 0 && i < 256) {
3887 i++;
3888 }
3889 if (i == 256) {
3890 return;
3891 }
3892 for (start = i++, streak = 1; i < 256; i++) {
3893 if (opcodeCoverage[i]) {
3894 streak++;
3895 } else {
3896 if (streak == 1) {
3897 sprintf(buf+strlen(buf), "%x,", start);
3898 } else {
3899 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3900 }
3901 streak = 0;
3902 while (opcodeCoverage[i] == 0 && i < 256) {
3903 i++;
3904 }
3905 if (i < 256) {
3906 streak = 1;
3907 start = i;
3908 }
3909 }
3910 }
3911 if (streak) {
3912 if (streak == 1) {
3913 sprintf(buf+strlen(buf), "%x", start);
3914 } else {
3915 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3916 }
3917 }
3918 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07003919 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003920 }
3921}
Ben Chengd7d426a2009-09-22 11:23:36 -07003922
3923/* Common initialization routine for an architecture family */
3924bool dvmCompilerArchInit()
3925{
3926 int i;
3927
Bill Buzbee1465db52009-09-23 17:17:35 -07003928 for (i = 0; i < kArmLast; i++) {
Ben Chengd7d426a2009-09-22 11:23:36 -07003929 if (EncodingMap[i].opCode != i) {
3930 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
3931 EncodingMap[i].name, i, EncodingMap[i].opCode);
Bill Buzbeefc519dc2010-03-06 23:30:57 -08003932 dvmAbort(); // OK to dvmAbort - build error
Ben Chengd7d426a2009-09-22 11:23:36 -07003933 }
3934 }
3935
Ben Cheng5d90c202009-11-22 23:31:11 -08003936 return dvmCompilerArchVariantInit();
3937}
3938
3939void *dvmCompilerGetInterpretTemplate()
3940{
3941 return (void*) ((int)gDvmJit.codeCache +
3942 templateEntryOffsets[TEMPLATE_INTERPRET]);
3943}
3944
3945/* Needed by the ld/st optmizatons */
3946ArmLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
3947{
3948 return genRegCopyNoInsert(cUnit, rDest, rSrc);
3949}
3950
3951/* Needed by the register allocator */
3952ArmLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
3953{
3954 return genRegCopy(cUnit, rDest, rSrc);
3955}
3956
3957/* Needed by the register allocator */
3958void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
3959 int srcLo, int srcHi)
3960{
3961 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
3962}
3963
3964void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
3965 int displacement, int rSrc, OpSize size)
3966{
3967 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
3968}
3969
3970void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
3971 int displacement, int rSrcLo, int rSrcHi)
3972{
3973 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
Ben Chengd7d426a2009-09-22 11:23:36 -07003974}