blob: 3d46240df65456e8870d6e62c4d30f1c5671fee3 [file] [log] [blame]
buzbee31a4a6f2012-02-28 15:36:15 -08001/*
2 * Copyright (C) 2012 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
17namespace art {
18
19/*
20 * This source files contains "gen" codegen routines that should
21 * be applicable to most targets. Only mid-level support utilities
22 * and "op" calls may be used here.
23 */
24
25#if defined(TARGET_ARM)
buzbee82488f52012-03-02 08:20:26 -080026LIR* opIT(CompilationUnit* cUnit, ArmConditionCode cond, const char* guide);
buzbee31a4a6f2012-02-28 15:36:15 -080027#endif
28
29LIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
30{
31 oatClobberCalleeSave(cUnit);
32 return opReg(cUnit, kOpBlx, reg);
33}
34
35/*
36 * Generate an kPseudoBarrier marker to indicate the boundary of special
37 * blocks.
38 */
39void genBarrier(CompilationUnit* cUnit)
40{
41 LIR* barrier = newLIR0(cUnit, kPseudoBarrier);
42 /* Mark all resources as being clobbered */
43 barrier->defMask = -1;
44}
45
buzbee31a4a6f2012-02-28 15:36:15 -080046
47/* Generate unconditional branch instructions */
buzbee82488f52012-03-02 08:20:26 -080048LIR* opUnconditionalBranch(CompilationUnit* cUnit, LIR* target)
buzbee31a4a6f2012-02-28 15:36:15 -080049{
50 LIR* branch = opNone(cUnit, kOpUncondBr);
51 branch->target = (LIR*) target;
52 return branch;
53}
54
buzbee5de34942012-03-01 14:51:57 -080055// FIXME: need to do some work to split out targets with
56// condition codes and those without
57#if defined(TARGET_ARM) || defined(TARGET_X86)
buzbee31a4a6f2012-02-28 15:36:15 -080058LIR* genCheck(CompilationUnit* cUnit, ConditionCode cCode, MIR* mir,
59 ThrowKind kind)
60{
buzbeea2ebdd72012-03-04 14:57:06 -080061 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
62 mir ? mir->offset : 0);
buzbee82488f52012-03-02 08:20:26 -080063 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080064 // Remember branch target - will process later
65 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
66 return branch;
67}
buzbee5de34942012-03-01 14:51:57 -080068#endif
buzbee31a4a6f2012-02-28 15:36:15 -080069
70LIR* genImmedCheck(CompilationUnit* cUnit, ConditionCode cCode,
71 int reg, int immVal, MIR* mir, ThrowKind kind)
72{
buzbeea2ebdd72012-03-04 14:57:06 -080073 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind, mir->offset);
buzbee31a4a6f2012-02-28 15:36:15 -080074 LIR* branch;
75 if (cCode == kCondAl) {
buzbee82488f52012-03-02 08:20:26 -080076 branch = opUnconditionalBranch(cUnit, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080077 } else {
buzbee82488f52012-03-02 08:20:26 -080078 branch = opCmpImmBranch(cUnit, cCode, reg, immVal, tgt);
buzbee31a4a6f2012-02-28 15:36:15 -080079 }
80 // Remember branch target - will process later
81 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
82 return branch;
83}
84
85/* Perform null-check on a register. */
86LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg, MIR* mir)
87{
88 if (!(cUnit->disableOpt & (1 << kNullCheckElimination)) &&
89 mir->optimizationFlags & MIR_IGNORE_NULL_CHECK) {
90 return NULL;
91 }
92 return genImmedCheck(cUnit, kCondEq, mReg, 0, mir, kThrowNullPointer);
93}
94
95/* Perform check on two registers */
96LIR* genRegRegCheck(CompilationUnit* cUnit, ConditionCode cCode,
97 int reg1, int reg2, MIR* mir, ThrowKind kind)
98{
buzbeea2ebdd72012-03-04 14:57:06 -080099 LIR* tgt = rawLIR(cUnit, 0, kPseudoThrowTarget, kind,
100 mir ? mir->offset : 0, reg1, reg2);
buzbee5de34942012-03-01 14:51:57 -0800101#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800102 LIR* branch = opCmpBranch(cUnit, cCode, reg1, reg2, tgt);
buzbee5de34942012-03-01 14:51:57 -0800103#else
buzbee31a4a6f2012-02-28 15:36:15 -0800104 opRegReg(cUnit, kOpCmp, reg1, reg2);
buzbee82488f52012-03-02 08:20:26 -0800105 LIR* branch = opCondBranch(cUnit, cCode, tgt);
buzbee5de34942012-03-01 14:51:57 -0800106#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800107 // Remember branch target - will process later
108 oatInsertGrowableList(cUnit, &cUnit->throwLaunchpads, (intptr_t)tgt);
109 return branch;
110}
111
112void genCompareAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
113 RegLocation rlSrc1, RegLocation rlSrc2, LIR* labelList)
114{
115 ConditionCode cond;
116 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
117 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800118 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -0800119 switch(opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800120 case Instruction::IF_EQ:
buzbee31a4a6f2012-02-28 15:36:15 -0800121 cond = kCondEq;
122 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800123 case Instruction::IF_NE:
buzbee31a4a6f2012-02-28 15:36:15 -0800124 cond = kCondNe;
125 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800126 case Instruction::IF_LT:
buzbee31a4a6f2012-02-28 15:36:15 -0800127 cond = kCondLt;
128 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800129 case Instruction::IF_GE:
buzbee31a4a6f2012-02-28 15:36:15 -0800130 cond = kCondGe;
131 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800132 case Instruction::IF_GT:
buzbee31a4a6f2012-02-28 15:36:15 -0800133 cond = kCondGt;
134 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800135 case Instruction::IF_LE:
buzbee31a4a6f2012-02-28 15:36:15 -0800136 cond = kCondLe;
137 break;
138 default:
139 cond = (ConditionCode)0;
140 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
141 }
buzbee5de34942012-03-01 14:51:57 -0800142#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800143 opCmpBranch(cUnit, cond, rlSrc1.lowReg, rlSrc2.lowReg,
144 &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800145#else
146 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
buzbee82488f52012-03-02 08:20:26 -0800147 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800148#endif
buzbee82488f52012-03-02 08:20:26 -0800149 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800150}
151
152void genCompareZeroAndBranch(CompilationUnit* cUnit, BasicBlock* bb, MIR* mir,
153 RegLocation rlSrc, LIR* labelList)
154{
155 ConditionCode cond;
156 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800157 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -0800158 switch(opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800159 case Instruction::IF_EQZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800160 cond = kCondEq;
161 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800162 case Instruction::IF_NEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800163 cond = kCondNe;
164 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800165 case Instruction::IF_LTZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800166 cond = kCondLt;
167 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800168 case Instruction::IF_GEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800169 cond = kCondGe;
170 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800171 case Instruction::IF_GTZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800172 cond = kCondGt;
173 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800174 case Instruction::IF_LEZ:
buzbee31a4a6f2012-02-28 15:36:15 -0800175 cond = kCondLe;
176 break;
177 default:
178 cond = (ConditionCode)0;
179 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
180 }
buzbee5de34942012-03-01 14:51:57 -0800181#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -0800182 opCmpImmBranch(cUnit, cond, rlSrc.lowReg, 0, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800183#else
184 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
buzbee82488f52012-03-02 08:20:26 -0800185 opCondBranch(cUnit, cond, &labelList[bb->taken->id]);
buzbee5de34942012-03-01 14:51:57 -0800186#endif
buzbee82488f52012-03-02 08:20:26 -0800187 opUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
buzbee31a4a6f2012-02-28 15:36:15 -0800188}
189
190void genIntToLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
191 RegLocation rlSrc)
192{
193 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
194 if (rlSrc.location == kLocPhysReg) {
buzbee82488f52012-03-02 08:20:26 -0800195 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800196 } else {
197 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
198 }
199 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
200 rlResult.lowReg, 31);
201 storeValueWide(cUnit, rlDest, rlResult);
202}
203
204void genIntNarrowing(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
205 RegLocation rlSrc)
206{
207 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
208 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
209 OpKind op = kOpInvalid;
210 switch(mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800211 case Instruction::INT_TO_BYTE:
buzbee31a4a6f2012-02-28 15:36:15 -0800212 op = kOp2Byte;
213 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800214 case Instruction::INT_TO_SHORT:
buzbee31a4a6f2012-02-28 15:36:15 -0800215 op = kOp2Short;
216 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800217 case Instruction::INT_TO_CHAR:
buzbee31a4a6f2012-02-28 15:36:15 -0800218 op = kOp2Char;
219 break;
220 default:
221 LOG(ERROR) << "Bad int conversion type";
222 }
223 opRegReg(cUnit, op, rlResult.lowReg, rlSrc.lowReg);
224 storeValue(cUnit, rlDest, rlResult);
225}
226
227/*
228 * Let helper function take care of everything. Will call
229 * Array::AllocFromCode(type_idx, method, count);
230 * Note: AllocFromCode will handle checks for errNegativeArraySize.
231 */
232void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
233 RegLocation rlSrc)
234{
235 oatFlushAllRegs(cUnit); /* Everything to home location */
236 uint32_t type_idx = mir->dalvikInsn.vC;
237 int rTgt;
238 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
239 cUnit->dex_cache,
240 *cUnit->dex_file,
241 type_idx)) {
242 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pAllocArrayFromCode));
243 } else {
244 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
245 pAllocArrayFromCodeWithAccessCheck));
246 }
247 loadCurrMethodDirect(cUnit, rARG1); // arg1 <- Method*
248 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_id
249 loadValueDirectFixed(cUnit, rlSrc, rARG2); // arg2 <- count
250 callRuntimeHelper(cUnit, rTgt);
251 RegLocation rlResult = oatGetReturn(cUnit);
252 storeValue(cUnit, rlDest, rlResult);
253}
254
255/*
256 * Similar to genNewArray, but with post-allocation initialization.
257 * Verifier guarantees we're dealing with an array class. Current
258 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
259 * Current code also throws internal unimp if not 'L', '[' or 'I'.
260 */
261void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
262{
263 DecodedInstruction* dInsn = &mir->dalvikInsn;
264 int elems = dInsn->vA;
265 int typeId = dInsn->vB;
266 oatFlushAllRegs(cUnit); /* Everything to home location */
267 int rTgt;
268 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
269 cUnit->dex_cache,
270 *cUnit->dex_file,
271 typeId)) {
272 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
273 pCheckAndAllocArrayFromCode));
274 } else {
275 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
276 pCheckAndAllocArrayFromCodeWithAccessCheck));
277 }
278 loadCurrMethodDirect(cUnit, rARG1); // arg1 <- Method*
279 loadConstant(cUnit, rARG0, typeId); // arg0 <- type_id
280 loadConstant(cUnit, rARG2, elems); // arg2 <- count
281 callRuntimeHelper(cUnit, rTgt);
282 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -0800283 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the
buzbee31a4a6f2012-02-28 15:36:15 -0800284 * return region. Because AllocFromCode placed the new array
285 * in rRET0, we'll just lock it into place. When debugger support is
286 * added, it may be necessary to additionally copy all return
287 * values to a home location in thread-local storage
288 */
289 oatLockTemp(cUnit, rRET0);
290
291 // TODO: use the correct component size, currently all supported types
292 // share array alignment with ints (see comment at head of function)
293 size_t component_size = sizeof(int32_t);
294
295 // Having a range of 0 is legal
296 if (isRange && (dInsn->vA > 0)) {
297 /*
298 * Bit of ugliness here. We're going generate a mem copy loop
299 * on the register range, but it is possible that some regs
300 * in the range have been promoted. This is unlikely, but
301 * before generating the copy, we'll just force a flush
302 * of any regs in the source range that have been promoted to
303 * home location.
304 */
305 for (unsigned int i = 0; i < dInsn->vA; i++) {
306 RegLocation loc = oatUpdateLoc(cUnit,
307 oatGetSrc(cUnit, mir, i));
308 if (loc.location == kLocPhysReg) {
309 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
310 loc.lowReg, kWord);
311 }
312 }
313 /*
314 * TUNING note: generated code here could be much improved, but
315 * this is an uncommon operation and isn't especially performance
316 * critical.
317 */
318 int rSrc = oatAllocTemp(cUnit);
319 int rDst = oatAllocTemp(cUnit);
320 int rIdx = oatAllocTemp(cUnit);
buzbee5de34942012-03-01 14:51:57 -0800321#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -0800322 int rVal = rLR; // Using a lot of temps, rLR is known free here
buzbee5de34942012-03-01 14:51:57 -0800323#else
324 int rVal = oatAllocTemp(cUnit);
325#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800326 // Set up source pointer
327 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
328 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
329 oatSRegOffset(cUnit, rlFirst.sRegLow));
330 // Set up the target pointer
331 opRegRegImm(cUnit, kOpAdd, rDst, rRET0,
332 Array::DataOffset(component_size).Int32Value());
333 // Set up the loop counter (known to be > 0)
334 loadConstant(cUnit, rIdx, dInsn->vA - 1);
335 // Generate the copy loop. Going backwards for convenience
336 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800337 // Copy next element
338 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
339 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
340#if defined(TARGET_ARM)
341 // Combine sub & test using sub setflags encoding here
342 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800343 opCondBranch(cUnit, kCondGe, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800344#else
buzbee5de34942012-03-01 14:51:57 -0800345 oatFreeTemp(cUnit, rVal);
buzbee31a4a6f2012-02-28 15:36:15 -0800346 opRegImm(cUnit, kOpSub, rIdx, 1);
buzbee82488f52012-03-02 08:20:26 -0800347 opCmpImmBranch(cUnit, kCondGe, rIdx, 0, target);
buzbee31a4a6f2012-02-28 15:36:15 -0800348#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800349 } else if (!isRange) {
350 // TUNING: interleave
351 for (unsigned int i = 0; i < dInsn->vA; i++) {
352 RegLocation rlArg = loadValue(cUnit,
353 oatGetSrc(cUnit, mir, i), kCoreReg);
354 storeBaseDisp(cUnit, rRET0,
355 Array::DataOffset(component_size).Int32Value() +
356 i * 4, rlArg.lowReg, kWord);
357 // If the loadValue caused a temp to be allocated, free it
358 if (oatIsTemp(cUnit, rlArg.lowReg)) {
359 oatFreeTemp(cUnit, rlArg.lowReg);
360 }
361 }
362 }
363}
364
365void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
366 bool isLongOrDouble, bool isObject)
367{
buzbeea7678db2012-03-05 15:35:46 -0800368#if defined(TARGET_X86)
369 UNIMPLEMENTED(WARNING) << "genSput";
370#else
buzbee31a4a6f2012-02-28 15:36:15 -0800371 int fieldOffset;
372 int ssbIndex;
373 bool isVolatile;
374 bool isReferrersClass;
375 uint32_t fieldIdx = mir->dalvikInsn.vB;
376
377 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
378 *cUnit->dex_file, *cUnit->dex_cache,
379 cUnit->code_item, cUnit->method_idx,
380 cUnit->access_flags);
381
382 bool fastPath =
383 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
384 fieldOffset, ssbIndex,
385 isReferrersClass, isVolatile, true);
386 if (fastPath && !SLOW_FIELD_PATH) {
387 DCHECK_GE(fieldOffset, 0);
388 int rBase;
389 int rMethod;
390 if (isReferrersClass) {
391 // Fast path, static storage base is this method's class
392 rMethod = loadCurrMethod(cUnit);
393 rBase = oatAllocTemp(cUnit);
394 loadWordDisp(cUnit, rMethod,
395 Method::DeclaringClassOffset().Int32Value(), rBase);
396 } else {
397 // Medium path, static storage base in a different class which
398 // requires checks that the other class is initialized.
399 DCHECK_GE(ssbIndex, 0);
400 // May do runtime call so everything to home locations.
401 oatFlushAllRegs(cUnit);
402 // Using fixed register to sync with possible call to runtime
403 // support.
404 rMethod = rARG1;
405 oatLockTemp(cUnit, rMethod);
406 loadCurrMethodDirect(cUnit, rMethod);
407 rBase = rARG0;
408 oatLockTemp(cUnit, rBase);
409 loadWordDisp(cUnit, rMethod,
410 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
411 rBase);
412 loadWordDisp(cUnit, rBase,
413 Array::DataOffset(sizeof(Object*)).Int32Value() + sizeof(int32_t*) *
414 ssbIndex, rBase);
415 // rBase now points at appropriate static storage base (Class*)
416 // or NULL if not initialized. Check for NULL and call helper if NULL.
417 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800418 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800419 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
420 pInitializeStaticStorage));
421 loadConstant(cUnit, rARG0, ssbIndex);
422 callRuntimeHelper(cUnit, rTgt);
423#if defined(TARGET_MIPS)
424 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800425 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800426#endif
427 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800428 branchOver->target = (LIR*)skipTarget;
429 }
430 // rBase now holds static storage base
431 oatFreeTemp(cUnit, rMethod);
432 if (isLongOrDouble) {
433 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
434 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
435 } else {
436 rlSrc = oatGetSrc(cUnit, mir, 0);
437 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
438 }
439//FIXME: need to generalize the barrier call
440 if (isVolatile) {
441 oatGenMemBarrier(cUnit, kST);
442 }
443 if (isLongOrDouble) {
444 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
445 rlSrc.highReg);
446 } else {
447 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
448 }
449 if (isVolatile) {
450 oatGenMemBarrier(cUnit, kSY);
451 }
452 if (isObject) {
453 markGCCard(cUnit, rlSrc.lowReg, rBase);
454 }
455 oatFreeTemp(cUnit, rBase);
456 } else {
457 oatFlushAllRegs(cUnit); // Everything to home locations
458 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
459 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
460 : OFFSETOF_MEMBER(Thread, pSet32Static));
461 int rTgt = loadHelper(cUnit, setterOffset);
462 loadConstant(cUnit, rARG0, fieldIdx);
463 if (isLongOrDouble) {
464 loadValueDirectWideFixed(cUnit, rlSrc, rARG2, rARG3);
465 } else {
466 loadValueDirect(cUnit, rlSrc, rARG1);
467 }
468 callRuntimeHelper(cUnit, rTgt);
469 }
buzbeea7678db2012-03-05 15:35:46 -0800470#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800471}
472
473void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
474 bool isLongOrDouble, bool isObject)
475{
476 int fieldOffset;
477 int ssbIndex;
478 bool isVolatile;
479 bool isReferrersClass;
480 uint32_t fieldIdx = mir->dalvikInsn.vB;
481
482 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
483 *cUnit->dex_file, *cUnit->dex_cache,
484 cUnit->code_item, cUnit->method_idx,
485 cUnit->access_flags);
486
487 bool fastPath =
488 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, &mUnit,
489 fieldOffset, ssbIndex,
490 isReferrersClass, isVolatile,
491 false);
492 if (fastPath && !SLOW_FIELD_PATH) {
493 DCHECK_GE(fieldOffset, 0);
494 int rBase;
495 int rMethod;
496 if (isReferrersClass) {
497 // Fast path, static storage base is this method's class
498 rMethod = loadCurrMethod(cUnit);
499 rBase = oatAllocTemp(cUnit);
500 loadWordDisp(cUnit, rMethod,
501 Method::DeclaringClassOffset().Int32Value(), rBase);
502 } else {
503 // Medium path, static storage base in a different class which
504 // requires checks that the other class is initialized
505 DCHECK_GE(ssbIndex, 0);
506 // May do runtime call so everything to home locations.
507 oatFlushAllRegs(cUnit);
508 // Using fixed register to sync with possible call to runtime
509 // support
510 rMethod = rARG1;
511 oatLockTemp(cUnit, rMethod);
512 loadCurrMethodDirect(cUnit, rMethod);
513 rBase = rARG0;
514 oatLockTemp(cUnit, rBase);
515 loadWordDisp(cUnit, rMethod,
516 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
517 rBase);
518 loadWordDisp(cUnit, rBase,
519 Array::DataOffset(sizeof(Object*)).Int32Value() +
520 sizeof(int32_t*) * ssbIndex,
521 rBase);
522 // rBase now points at appropriate static storage base (Class*)
523 // or NULL if not initialized. Check for NULL and call helper if NULL.
524 // TUNING: fast path should fall through
buzbee82488f52012-03-02 08:20:26 -0800525 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rBase, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800526 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
527 pInitializeStaticStorage));
528 loadConstant(cUnit, rARG0, ssbIndex);
529 callRuntimeHelper(cUnit, rTgt);
530#if defined(TARGET_MIPS)
531 // For Arm, rRET0 = rARG0 = rBASE, for Mips, we need to copy
buzbee82488f52012-03-02 08:20:26 -0800532 opRegCopy(cUnit, rBase, rRET0);
buzbee31a4a6f2012-02-28 15:36:15 -0800533#endif
534 LIR* skipTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800535 branchOver->target = (LIR*)skipTarget;
536 }
537 // rBase now holds static storage base
538 oatFreeTemp(cUnit, rMethod);
539 rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
540 : oatGetDest(cUnit, mir, 0);
541 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
542 if (isVolatile) {
543 oatGenMemBarrier(cUnit, kSY);
544 }
545 if (isLongOrDouble) {
546 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
547 rlResult.highReg, INVALID_SREG);
548 } else {
549 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
550 }
551 oatFreeTemp(cUnit, rBase);
552 if (isLongOrDouble) {
553 storeValueWide(cUnit, rlDest, rlResult);
554 } else {
555 storeValue(cUnit, rlDest, rlResult);
556 }
557 } else {
558 oatFlushAllRegs(cUnit); // Everything to home locations
559 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
560 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
561 : OFFSETOF_MEMBER(Thread, pGet32Static));
562 int rTgt = loadHelper(cUnit, getterOffset);
563 loadConstant(cUnit, rARG0, fieldIdx);
564 callRuntimeHelper(cUnit, rTgt);
565 if (isLongOrDouble) {
566 RegLocation rlResult = oatGetReturnWide(cUnit);
567 storeValueWide(cUnit, rlDest, rlResult);
568 } else {
569 RegLocation rlResult = oatGetReturn(cUnit);
570 storeValue(cUnit, rlDest, rlResult);
571 }
572 }
573}
574
575
576// Debugging routine - if null target, branch to DebugMe
577void genShowTarget(CompilationUnit* cUnit)
578{
buzbeea7678db2012-03-05 15:35:46 -0800579#if defined(TARGET_X86)
580 UNIMPLEMENTED(WARNING) << "genShowTarget";
581#else
buzbee0398c422012-03-02 15:22:47 -0800582 LIR* branchOver = opCmpImmBranch(cUnit, kCondNe, rINVOKE_TGT, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800583 loadWordDisp(cUnit, rSELF,
buzbee0398c422012-03-02 15:22:47 -0800584 OFFSETOF_MEMBER(Thread, pDebugMe), rINVOKE_TGT);
buzbee31a4a6f2012-02-28 15:36:15 -0800585 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800586 branchOver->target = (LIR*)target;
buzbeea7678db2012-03-05 15:35:46 -0800587#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800588}
589
590void genThrowVerificationError(CompilationUnit* cUnit, MIR* mir)
591{
592 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
593 pThrowVerificationErrorFromCode));
594 loadConstant(cUnit, rARG0, mir->dalvikInsn.vA);
595 loadConstant(cUnit, rARG1, mir->dalvikInsn.vB);
596 callRuntimeHelper(cUnit, rTgt);
597}
598
599void handleSuspendLaunchpads(CompilationUnit *cUnit)
600{
buzbeea7678db2012-03-05 15:35:46 -0800601#if defined(TARGET_X86)
602 UNIMPLEMENTED(WARNING);
603#else
buzbee31a4a6f2012-02-28 15:36:15 -0800604 LIR** suspendLabel =
605 (LIR **) cUnit->suspendLaunchpads.elemList;
606 int numElems = cUnit->suspendLaunchpads.numUsed;
607
608 for (int i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800609 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800610 LIR* lab = suspendLabel[i];
611 LIR* resumeLab = (LIR*)lab->operands[0];
612 cUnit->currentDalvikOffset = lab->operands[1];
613 oatAppendLIR(cUnit, (LIR *)lab);
614 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
615 pTestSuspendFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -0800616 opReg(cUnit, kOpBlx, rTgt);
buzbee82488f52012-03-02 08:20:26 -0800617 opUnconditionalBranch(cUnit, resumeLab);
buzbee31a4a6f2012-02-28 15:36:15 -0800618 }
buzbeea7678db2012-03-05 15:35:46 -0800619#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800620}
621
622void handleThrowLaunchpads(CompilationUnit *cUnit)
623{
624 LIR** throwLabel = (LIR **) cUnit->throwLaunchpads.elemList;
625 int numElems = cUnit->throwLaunchpads.numUsed;
626 int i;
627
628 for (i = 0; i < numElems; i++) {
buzbeec5159d52012-03-03 11:48:39 -0800629 oatResetRegPool(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -0800630 LIR* lab = throwLabel[i];
631 cUnit->currentDalvikOffset = lab->operands[1];
632 oatAppendLIR(cUnit, (LIR *)lab);
633 int funcOffset = 0;
634 int v1 = lab->operands[2];
635 int v2 = lab->operands[3];
636 switch(lab->operands[0]) {
637 case kThrowNullPointer:
638 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
639 break;
640 case kThrowArrayBounds:
buzbee5de34942012-03-01 14:51:57 -0800641 if (v2 != rARG0) {
buzbee82488f52012-03-02 08:20:26 -0800642 opRegCopy(cUnit, rARG0, v1);
643 opRegCopy(cUnit, rARG1, v2);
buzbee31a4a6f2012-02-28 15:36:15 -0800644 } else {
buzbee5de34942012-03-01 14:51:57 -0800645 if (v1 == rARG1) {
buzbee31a4a6f2012-02-28 15:36:15 -0800646#if defined(TARGET_ARM)
647 int rTmp = r12;
648#else
649 int rTmp = oatAllocTemp(cUnit);
650#endif
buzbee82488f52012-03-02 08:20:26 -0800651 opRegCopy(cUnit, rTmp, v1);
652 opRegCopy(cUnit, rARG1, v2);
653 opRegCopy(cUnit, rARG0, rTmp);
buzbee31a4a6f2012-02-28 15:36:15 -0800654 } else {
buzbee82488f52012-03-02 08:20:26 -0800655 opRegCopy(cUnit, rARG1, v2);
656 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800657 }
658 }
659 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
660 break;
661 case kThrowDivZero:
662 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
663 break;
664 case kThrowVerificationError:
665 loadConstant(cUnit, rARG0, v1);
666 loadConstant(cUnit, rARG1, v2);
667 funcOffset =
668 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
669 break;
670 case kThrowNegArraySize:
buzbee82488f52012-03-02 08:20:26 -0800671 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800672 funcOffset =
673 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
674 break;
675 case kThrowNoSuchMethod:
buzbee82488f52012-03-02 08:20:26 -0800676 opRegCopy(cUnit, rARG0, v1);
buzbee31a4a6f2012-02-28 15:36:15 -0800677 funcOffset =
678 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
679 break;
680 case kThrowStackOverflow:
681 funcOffset =
682 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
683 // Restore stack alignment
684 opRegImm(cUnit, kOpAdd, rSP,
685 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
686 break;
687 default:
688 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
689 }
690 int rTgt = loadHelper(cUnit, funcOffset);
691 callRuntimeHelper(cUnit, rTgt);
buzbee0398c422012-03-02 15:22:47 -0800692 oatFreeTemp(cUnit, rTgt);
buzbee31a4a6f2012-02-28 15:36:15 -0800693 }
694}
695
696/* Needed by the Assembler */
697void oatSetupResourceMasks(LIR* lir)
698{
699 setupResourceMasks(lir);
700}
701
702void genIGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
703 RegLocation rlDest, RegLocation rlObj,
704 bool isLongOrDouble, bool isObject)
705{
706 int fieldOffset;
707 bool isVolatile;
708 uint32_t fieldIdx = mir->dalvikInsn.vC;
709
710 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
711 *cUnit->dex_file, *cUnit->dex_cache,
712 cUnit->code_item, cUnit->method_idx,
713 cUnit->access_flags);
714
715 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
716 fieldOffset, isVolatile, false);
717
718 if (fastPath && !SLOW_FIELD_PATH) {
719 RegLocation rlResult;
720 RegisterClass regClass = oatRegClassBySize(size);
721 DCHECK_GE(fieldOffset, 0);
722 rlObj = loadValue(cUnit, rlObj, kCoreReg);
723 if (isLongOrDouble) {
724 DCHECK(rlDest.wide);
725 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
726 int regPtr = oatAllocTemp(cUnit);
727 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
728 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
729 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
730 if (isVolatile) {
731 oatGenMemBarrier(cUnit, kSY);
732 }
733 oatFreeTemp(cUnit, regPtr);
734 storeValueWide(cUnit, rlDest, rlResult);
735 } else {
736 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
737 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
738 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
739 kWord, rlObj.sRegLow);
740 if (isVolatile) {
741 oatGenMemBarrier(cUnit, kSY);
742 }
743 storeValue(cUnit, rlDest, rlResult);
744 }
745 } else {
746 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Instance) :
747 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjInstance)
748 : OFFSETOF_MEMBER(Thread, pGet32Instance));
749 int rTgt = loadHelper(cUnit, getterOffset);
750 loadValueDirect(cUnit, rlObj, rARG1);
751 loadConstant(cUnit, rARG0, fieldIdx);
752 callRuntimeHelper(cUnit, rTgt);
753 if (isLongOrDouble) {
754 RegLocation rlResult = oatGetReturnWide(cUnit);
755 storeValueWide(cUnit, rlDest, rlResult);
756 } else {
757 RegLocation rlResult = oatGetReturn(cUnit);
758 storeValue(cUnit, rlDest, rlResult);
759 }
760 }
761}
762
763void genIPut(CompilationUnit* cUnit, MIR* mir, OpSize size, RegLocation rlSrc,
764 RegLocation rlObj, bool isLongOrDouble, bool isObject)
765{
buzbeea7678db2012-03-05 15:35:46 -0800766#if defined(TARGET_X86)
767 UNIMPLEMENTED(WARNING);
768#else
buzbee31a4a6f2012-02-28 15:36:15 -0800769 int fieldOffset;
770 bool isVolatile;
771 uint32_t fieldIdx = mir->dalvikInsn.vC;
772
773 OatCompilationUnit mUnit(cUnit->class_loader, cUnit->class_linker,
774 *cUnit->dex_file, *cUnit->dex_cache,
775 cUnit->code_item, cUnit->method_idx,
776 cUnit->access_flags);
777
778 bool fastPath = cUnit->compiler->ComputeInstanceFieldInfo(fieldIdx, &mUnit,
779 fieldOffset, isVolatile, true);
780 if (fastPath && !SLOW_FIELD_PATH) {
781 RegisterClass regClass = oatRegClassBySize(size);
782 DCHECK_GE(fieldOffset, 0);
783 rlObj = loadValue(cUnit, rlObj, kCoreReg);
784 if (isLongOrDouble) {
785 int regPtr;
786 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
787 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
788 regPtr = oatAllocTemp(cUnit);
789 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
790 if (isVolatile) {
791 oatGenMemBarrier(cUnit, kST);
792 }
793 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
794 if (isVolatile) {
795 oatGenMemBarrier(cUnit, kSY);
796 }
797 oatFreeTemp(cUnit, regPtr);
798 } else {
799 rlSrc = loadValue(cUnit, rlSrc, regClass);
800 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null? */
801 if (isVolatile) {
802 oatGenMemBarrier(cUnit, kST);
803 }
804 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
805 if (isVolatile) {
806 oatGenMemBarrier(cUnit, kSY);
807 }
808 }
809 } else {
810 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Instance) :
811 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjInstance)
812 : OFFSETOF_MEMBER(Thread, pSet32Instance));
813 int rTgt = loadHelper(cUnit, setterOffset);
814 loadValueDirect(cUnit, rlObj, rARG1);
815 if (isLongOrDouble) {
816 loadValueDirectWide(cUnit, rlSrc, rARG2, rARG3);
817 } else {
818 loadValueDirect(cUnit, rlSrc, rARG2);
819 }
820 loadConstant(cUnit, rARG0, fieldIdx);
821 callRuntimeHelper(cUnit, rTgt);
822 }
buzbeea7678db2012-03-05 15:35:46 -0800823#endif
buzbee31a4a6f2012-02-28 15:36:15 -0800824}
825
826void genConstClass(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
827 RegLocation rlSrc)
828{
829 uint32_t type_idx = mir->dalvikInsn.vB;
830 int mReg = loadCurrMethod(cUnit);
831 int resReg = oatAllocTemp(cUnit);
832 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
833 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
834 cUnit->dex_cache,
835 *cUnit->dex_file,
836 type_idx)) {
837 // Call out to helper which resolves type and verifies access.
838 // Resolved type returned in rRET0.
839 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
840 pInitializeTypeAndVerifyAccessFromCode));
buzbee82488f52012-03-02 08:20:26 -0800841 opRegCopy(cUnit, rARG1, mReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800842 loadConstant(cUnit, rARG0, type_idx);
843 callRuntimeHelper(cUnit, rTgt);
844 RegLocation rlResult = oatGetReturn(cUnit);
845 storeValue(cUnit, rlDest, rlResult);
846 } else {
847 // We're don't need access checks, load type from dex cache
848 int32_t dex_cache_offset =
849 Method::DexCacheResolvedTypesOffset().Int32Value();
850 loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
851 int32_t offset_of_type =
852 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
853 * type_idx);
854 loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
855 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->dex_cache,
856 type_idx) || SLOW_TYPE_PATH) {
857 // Slow path, at runtime test if type is null and if so initialize
858 oatFlushAllRegs(cUnit);
buzbee82488f52012-03-02 08:20:26 -0800859 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rlResult.lowReg, 0,
860 NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800861 // Resolved, store and hop over following code
862 storeValue(cUnit, rlDest, rlResult);
buzbee82488f52012-03-02 08:20:26 -0800863 LIR* branch2 = opUnconditionalBranch(cUnit,0);
buzbee31a4a6f2012-02-28 15:36:15 -0800864 // TUNING: move slow path to end & remove unconditional branch
865 LIR* target1 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee5de34942012-03-01 14:51:57 -0800866 // Call out to helper, which will return resolved type in rARG0
buzbee31a4a6f2012-02-28 15:36:15 -0800867 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
868 pInitializeTypeFromCode));
buzbee82488f52012-03-02 08:20:26 -0800869 opRegCopy(cUnit, rARG1, mReg);
buzbee31a4a6f2012-02-28 15:36:15 -0800870 loadConstant(cUnit, rARG0, type_idx);
871 callRuntimeHelper(cUnit, rTgt);
872 RegLocation rlResult = oatGetReturn(cUnit);
873 storeValue(cUnit, rlDest, rlResult);
874 // Rejoin code paths
875 LIR* target2 = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800876 branch1->target = (LIR*)target1;
877 branch2->target = (LIR*)target2;
878 } else {
879 // Fast path, we're done - just store result
880 storeValue(cUnit, rlDest, rlResult);
881 }
882 }
883}
884void genConstString(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
885 RegLocation rlSrc)
886{
887 /* NOTE: Most strings should be available at compile time */
888 uint32_t string_idx = mir->dalvikInsn.vB;
889 int32_t offset_of_string = Array::DataOffset(sizeof(String*)).Int32Value() +
890 (sizeof(String*) * string_idx);
891 if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(
892 cUnit->dex_cache, string_idx) || SLOW_STRING_PATH) {
893 // slow path, resolve string if not in dex cache
894 oatFlushAllRegs(cUnit);
895 oatLockCallTemps(cUnit); // Using explicit registers
896 loadCurrMethodDirect(cUnit, rARG2);
897 loadWordDisp(cUnit, rARG2,
898 Method::DexCacheStringsOffset().Int32Value(), rARG0);
899 // Might call out to helper, which will return resolved string in rRET0
900 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
901 pResolveStringFromCode));
902 loadWordDisp(cUnit, rRET0, offset_of_string, rARG0);
903 loadConstant(cUnit, rARG1, string_idx);
904#if defined(TARGET_ARM)
905 opRegImm(cUnit, kOpCmp, rRET0, 0); // Is resolved?
906 genBarrier(cUnit);
907 // For testing, always force through helper
908 if (!EXERCISE_SLOWEST_STRING_PATH) {
buzbee82488f52012-03-02 08:20:26 -0800909 opIT(cUnit, kArmCondEq, "T");
buzbee31a4a6f2012-02-28 15:36:15 -0800910 }
buzbee82488f52012-03-02 08:20:26 -0800911 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -0800912 opReg(cUnit, kOpBlx, rTgt); // .eq, helper(Method*, string_idx)
913#else
buzbee82488f52012-03-02 08:20:26 -0800914 LIR* branch = opCmpImmBranch(cUnit, kCondNe, rRET0, 0, NULL);
915 opRegCopy(cUnit, rARG0, rARG2); // .eq
buzbee31a4a6f2012-02-28 15:36:15 -0800916 opReg(cUnit, kOpBlx, rTgt);
917 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -0800918 branch->target = target;
919#endif
920 genBarrier(cUnit);
buzbee86a4bce2012-03-06 18:15:00 -0800921 storeValue(cUnit, rlDest, oatGetReturn(cUnit));
buzbee31a4a6f2012-02-28 15:36:15 -0800922 } else {
923 int mReg = loadCurrMethod(cUnit);
924 int resReg = oatAllocTemp(cUnit);
925 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
926 loadWordDisp(cUnit, mReg,
927 Method::DexCacheStringsOffset().Int32Value(), resReg);
928 loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
929 storeValue(cUnit, rlDest, rlResult);
930 }
931}
932
933/*
934 * Let helper function take care of everything. Will
935 * call Class::NewInstanceFromCode(type_idx, method);
936 */
937void genNewInstance(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest)
938{
939 oatFlushAllRegs(cUnit); /* Everything to home location */
940 uint32_t type_idx = mir->dalvikInsn.vB;
941 // alloc will always check for resolution, do we also need to verify
942 // access because the verifier was unable to?
943 int rTgt;
944 if (cUnit->compiler->CanAccessInstantiableTypeWithoutChecks(
945 cUnit->method_idx, cUnit->dex_cache, *cUnit->dex_file, type_idx)) {
946 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode));
947 } else {
948 rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
949 pAllocObjectFromCodeWithAccessCheck));
950 }
951 loadCurrMethodDirect(cUnit, rARG1); // arg1 <= Method*
952 loadConstant(cUnit, rARG0, type_idx); // arg0 <- type_idx
953 callRuntimeHelper(cUnit, rTgt);
954 RegLocation rlResult = oatGetReturn(cUnit);
955 storeValue(cUnit, rlDest, rlResult);
956}
957
958void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
959 RegLocation rlSrc)
960{
961 oatFlushAllRegs(cUnit);
962 // May generate a call - use explicit registers
963 oatLockCallTemps(cUnit);
964 uint32_t type_idx = mir->dalvikInsn.vC;
buzbee5de34942012-03-01 14:51:57 -0800965 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
buzbee31a4a6f2012-02-28 15:36:15 -0800966 int classReg = rARG2; // rARG2 will hold the Class*
967 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
968 cUnit->dex_cache,
969 *cUnit->dex_file,
970 type_idx)) {
971 // Check we have access to type_idx and if not throw IllegalAccessError,
buzbee5de34942012-03-01 14:51:57 -0800972 // returns Class* in rARG0
buzbee31a4a6f2012-02-28 15:36:15 -0800973 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
974 pInitializeTypeAndVerifyAccessFromCode));
975 loadConstant(cUnit, rARG0, type_idx);
976 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
buzbee82488f52012-03-02 08:20:26 -0800977 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee5de34942012-03-01 14:51:57 -0800978 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
buzbee31a4a6f2012-02-28 15:36:15 -0800979 } else {
buzbee5de34942012-03-01 14:51:57 -0800980 // Load dex cache entry into classReg (rARG2)
buzbee31a4a6f2012-02-28 15:36:15 -0800981 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
982 loadWordDisp(cUnit, rARG1,
983 Method::DexCacheResolvedTypesOffset().Int32Value(),
984 classReg);
985 int32_t offset_of_type =
986 Array::DataOffset(sizeof(Class*)).Int32Value() + (sizeof(Class*)
987 * type_idx);
988 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
989 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
990 cUnit->dex_cache, type_idx)) {
991 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -0800992 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -0800993 // Not resolved
994 // Call out to helper, which will return resolved type in rRET0
995 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
996 pInitializeTypeFromCode));
997 loadConstant(cUnit, rARG0, type_idx);
998 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
buzbee82488f52012-03-02 08:20:26 -0800999 opRegCopy(cUnit, rARG2, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001000 loadValueDirectFixed(cUnit, rlSrc, rARG0); /* reload Ref */
1001 // Rejoin code paths
1002 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001003 hopBranch->target = (LIR*)hopTarget;
1004 }
1005 }
1006 /* rARG0 is ref, rARG2 is class. If ref==null, use directly as bool result */
buzbee82488f52012-03-02 08:20:26 -08001007 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001008 /* load object->clazz */
1009 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1010 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1011 /* rARG0 is ref, rARG1 is ref->clazz, rARG2 is class */
buzbee0398c422012-03-02 15:22:47 -08001012#if defined(TARGET_ARM)
1013 /* Uses conditional nullification */
buzbee31a4a6f2012-02-28 15:36:15 -08001014 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1015 pInstanceofNonTrivialFromCode));
buzbee31a4a6f2012-02-28 15:36:15 -08001016 opRegReg(cUnit, kOpCmp, rARG1, rARG2); // Same?
buzbee82488f52012-03-02 08:20:26 -08001017 opIT(cUnit, kArmCondEq, "EE"); // if-convert the test
buzbee31a4a6f2012-02-28 15:36:15 -08001018 loadConstant(cUnit, rARG0, 1); // .eq case - load true
buzbee82488f52012-03-02 08:20:26 -08001019 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
buzbee31a4a6f2012-02-28 15:36:15 -08001020 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001021#else
buzbee0398c422012-03-02 15:22:47 -08001022 /* Uses branchovers */
1023 loadConstant(cUnit, rARG0, 1); // assume true
1024 LIR* branchover = opCmpBranch(cUnit, kCondEq, rARG1, rARG2, NULL);
1025 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1026 pInstanceofNonTrivialFromCode));
1027 opRegCopy(cUnit, rARG0, rARG2); // .ne case - arg0 <= class
1028 opReg(cUnit, kOpBlx, rTgt); // .ne case: helper(class, ref->class)
buzbee31a4a6f2012-02-28 15:36:15 -08001029#endif
buzbee0398c422012-03-02 15:22:47 -08001030 oatClobberCalleeSave(cUnit);
1031 /* branch targets here */
buzbee31a4a6f2012-02-28 15:36:15 -08001032 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001033 RegLocation rlResult = oatGetReturn(cUnit);
1034 storeValue(cUnit, rlDest, rlResult);
buzbee0398c422012-03-02 15:22:47 -08001035 branch1->target = target;
1036#if !defined(TARGET_ARM)
1037 branchover->target = target;
1038#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001039}
1040
1041void genCheckCast(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1042{
1043 oatFlushAllRegs(cUnit);
1044 // May generate a call - use explicit registers
1045 oatLockCallTemps(cUnit);
1046 uint32_t type_idx = mir->dalvikInsn.vB;
1047 loadCurrMethodDirect(cUnit, rARG1); // rARG1 <= current Method*
1048 int classReg = rARG2; // rARG2 will hold the Class*
1049 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
1050 cUnit->dex_cache,
1051 *cUnit->dex_file,
1052 type_idx)) {
1053 // Check we have access to type_idx and if not throw IllegalAccessError,
1054 // returns Class* in rRET0
1055 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1056 pInitializeTypeAndVerifyAccessFromCode));
1057 loadConstant(cUnit, rARG0, type_idx);
1058 callRuntimeHelper(cUnit, rTgt); // InitializeTypeAndVerifyAccess(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001059 opRegCopy(cUnit, classReg, rRET0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001060 } else {
1061 // Load dex cache entry into classReg (rARG2)
1062 loadWordDisp(cUnit, rARG1,
1063 Method::DexCacheResolvedTypesOffset().Int32Value(),
1064 classReg);
1065 int32_t offset_of_type =
1066 Array::DataOffset(sizeof(Class*)).Int32Value() +
1067 (sizeof(Class*) * type_idx);
1068 loadWordDisp(cUnit, classReg, offset_of_type, classReg);
1069 if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(
1070 cUnit->dex_cache, type_idx)) {
1071 // Need to test presence of type in dex cache at runtime
buzbee82488f52012-03-02 08:20:26 -08001072 LIR* hopBranch = opCmpImmBranch(cUnit, kCondNe, classReg, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001073 // Not resolved
buzbee5de34942012-03-01 14:51:57 -08001074 // Call out to helper, which will return resolved type in rARG0
1075 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode));
1076 loadConstant(cUnit, rARG0, type_idx);
1077 callRuntimeHelper(cUnit, rTgt); // InitializeTypeFromCode(idx, method)
buzbee82488f52012-03-02 08:20:26 -08001078 opRegCopy(cUnit, classReg, rARG0); // Align usage with fast path
buzbee31a4a6f2012-02-28 15:36:15 -08001079 // Rejoin code paths
1080 LIR* hopTarget = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001081 hopBranch->target = (LIR*)hopTarget;
1082 }
1083 }
buzbee5de34942012-03-01 14:51:57 -08001084 // At this point, classReg (rARG2) has class
buzbee31a4a6f2012-02-28 15:36:15 -08001085 loadValueDirectFixed(cUnit, rlSrc, rARG0); // rARG0 <= ref
1086 /* Null is OK - continue */
buzbee82488f52012-03-02 08:20:26 -08001087 LIR* branch1 = opCmpImmBranch(cUnit, kCondEq, rARG0, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08001088 /* load object->clazz */
1089 DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
1090 loadWordDisp(cUnit, rARG0, Object::ClassOffset().Int32Value(), rARG1);
1091 /* rARG1 now contains object->clazz */
1092 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1093 pCheckCastFromCode));
buzbee5de34942012-03-01 14:51:57 -08001094#if defined(TARGET_MIPS)
buzbee82488f52012-03-02 08:20:26 -08001095 LIR* branch2 = opCmpBranch(cUnit, kCondEq, rARG1, classReg, NULL);
buzbee5de34942012-03-01 14:51:57 -08001096#else
buzbee31a4a6f2012-02-28 15:36:15 -08001097 opRegReg(cUnit, kOpCmp, rARG1, classReg);
buzbee82488f52012-03-02 08:20:26 -08001098 LIR* branch2 = opCondBranch(cUnit, kCondEq, NULL); /* If eq, trivial yes */
buzbee5de34942012-03-01 14:51:57 -08001099#endif
buzbee82488f52012-03-02 08:20:26 -08001100 opRegCopy(cUnit, rARG0, rARG1);
1101 opRegCopy(cUnit, rARG1, rARG2);
buzbee31a4a6f2012-02-28 15:36:15 -08001102 callRuntimeHelper(cUnit, rTgt);
1103 /* branch target here */
1104 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08001105 branch1->target = (LIR*)target;
1106 branch2->target = (LIR*)target;
1107}
1108
1109
1110void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
1111{
1112 oatFlushAllRegs(cUnit);
1113 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread, pDeliverException));
1114 loadValueDirectFixed(cUnit, rlSrc, rARG0); // Get exception object
1115 callRuntimeHelper(cUnit, rTgt); // art_deliver_exception(exception);
1116}
1117
1118/*
1119 * Generate array store
1120 *
1121 */
1122void genArrayObjPut(CompilationUnit* cUnit, MIR* mir, RegLocation rlArray,
1123 RegLocation rlIndex, RegLocation rlSrc, int scale)
1124{
1125 RegisterClass regClass = oatRegClassBySize(kWord);
1126 int lenOffset = Array::LengthOffset().Int32Value();
1127 int dataOffset = Array::DataOffset(sizeof(Object*)).Int32Value();
1128
1129 oatFlushAllRegs(cUnit);
1130 /* Make sure it's a legal object Put. Use direct regs at first */
1131 loadValueDirectFixed(cUnit, rlArray, rARG1);
1132 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1133
1134 /* null array object? */
1135 genNullCheck(cUnit, rlArray.sRegLow, rARG1, mir);
1136 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
1137 pCanPutArrayElementFromCode));
1138 /* Get the array's clazz */
1139 loadWordDisp(cUnit, rARG1, Object::ClassOffset().Int32Value(), rARG1);
1140 callRuntimeHelper(cUnit, rTgt);
1141 oatFreeTemp(cUnit, rARG0);
1142 oatFreeTemp(cUnit, rARG1);
1143
1144 // Now, redo loadValues in case they didn't survive the call
1145
1146 int regPtr;
1147 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1148 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1149
1150 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1151 oatClobber(cUnit, rlArray.lowReg);
1152 regPtr = rlArray.lowReg;
1153 } else {
1154 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001155 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001156 }
1157
1158 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1159 int regLen = oatAllocTemp(cUnit);
1160 //NOTE: max live temps(4) here.
1161 /* Get len */
1162 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1163 /* regPtr -> array data */
1164 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1165 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1166 kThrowArrayBounds);
1167 oatFreeTemp(cUnit, regLen);
1168 } else {
1169 /* regPtr -> array data */
1170 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1171 }
1172 /* at this point, regPtr points to array, 2 live temps */
1173 rlSrc = loadValue(cUnit, rlSrc, regClass);
1174 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1175 scale, kWord);
1176}
1177
1178/*
1179 * Generate array load
1180 */
1181void genArrayGet(CompilationUnit* cUnit, MIR* mir, OpSize size,
1182 RegLocation rlArray, RegLocation rlIndex,
1183 RegLocation rlDest, int scale)
1184{
1185 RegisterClass regClass = oatRegClassBySize(size);
1186 int lenOffset = Array::LengthOffset().Int32Value();
1187 int dataOffset;
1188 RegLocation rlResult;
1189 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1190 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1191 int regPtr;
1192
1193 if (size == kLong || size == kDouble) {
1194 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1195 } else {
1196 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1197 }
1198
1199 /* null object? */
1200 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1201
1202 regPtr = oatAllocTemp(cUnit);
1203
1204 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1205 int regLen = oatAllocTemp(cUnit);
1206 /* Get len */
1207 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1208 /* regPtr -> array data */
1209 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1210 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1211 kThrowArrayBounds);
1212 oatFreeTemp(cUnit, regLen);
1213 } else {
1214 /* regPtr -> array data */
1215 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1216 }
1217 oatFreeTemp(cUnit, rlArray.lowReg);
1218 if ((size == kLong) || (size == kDouble)) {
1219 if (scale) {
1220 int rNewIndex = oatAllocTemp(cUnit);
1221 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1222 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1223 oatFreeTemp(cUnit, rNewIndex);
1224 } else {
1225 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1226 }
1227 oatFreeTemp(cUnit, rlIndex.lowReg);
1228 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1229
1230 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1231
1232 oatFreeTemp(cUnit, regPtr);
1233 storeValueWide(cUnit, rlDest, rlResult);
1234 } else {
1235 rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
1236
1237 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1238 scale, size);
1239
1240 oatFreeTemp(cUnit, regPtr);
1241 storeValue(cUnit, rlDest, rlResult);
1242 }
1243}
1244
1245/*
1246 * Generate array store
1247 *
1248 */
1249void genArrayPut(CompilationUnit* cUnit, MIR* mir, OpSize size,
1250 RegLocation rlArray, RegLocation rlIndex,
1251 RegLocation rlSrc, int scale)
1252{
1253 RegisterClass regClass = oatRegClassBySize(size);
1254 int lenOffset = Array::LengthOffset().Int32Value();
1255 int dataOffset;
1256
1257 if (size == kLong || size == kDouble) {
1258 dataOffset = Array::DataOffset(sizeof(int64_t)).Int32Value();
1259 } else {
1260 dataOffset = Array::DataOffset(sizeof(int32_t)).Int32Value();
1261 }
1262
1263 int regPtr;
1264 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1265 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1266
1267 if (oatIsTemp(cUnit, rlArray.lowReg)) {
1268 oatClobber(cUnit, rlArray.lowReg);
1269 regPtr = rlArray.lowReg;
1270 } else {
1271 regPtr = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001272 opRegCopy(cUnit, regPtr, rlArray.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001273 }
1274
1275 /* null object? */
1276 genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
1277
1278 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1279 int regLen = oatAllocTemp(cUnit);
1280 //NOTE: max live temps(4) here.
1281 /* Get len */
1282 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1283 /* regPtr -> array data */
1284 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1285 genRegRegCheck(cUnit, kCondCs, rlIndex.lowReg, regLen, mir,
1286 kThrowArrayBounds);
1287 oatFreeTemp(cUnit, regLen);
1288 } else {
1289 /* regPtr -> array data */
1290 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1291 }
1292 /* at this point, regPtr points to array, 2 live temps */
1293 if ((size == kLong) || (size == kDouble)) {
1294 //TUNING: specific wide routine that can handle fp regs
1295 if (scale) {
1296 int rNewIndex = oatAllocTemp(cUnit);
1297 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1298 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1299 oatFreeTemp(cUnit, rNewIndex);
1300 } else {
1301 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1302 }
1303 rlSrc = loadValueWide(cUnit, rlSrc, regClass);
1304
1305 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1306
1307 oatFreeTemp(cUnit, regPtr);
1308 } else {
1309 rlSrc = loadValue(cUnit, rlSrc, regClass);
1310
1311 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1312 scale, size);
1313 }
1314}
1315
1316void genLong3Addr(CompilationUnit* cUnit, MIR* mir, OpKind firstOp,
1317 OpKind secondOp, RegLocation rlDest,
1318 RegLocation rlSrc1, RegLocation rlSrc2)
1319{
1320 RegLocation rlResult;
1321#if defined(TARGET_ARM)
1322 /*
1323 * NOTE: This is the one place in the code in which we might have
1324 * as many as six live temporary registers. There are 5 in the normal
1325 * set for Arm. Until we have spill capabilities, temporarily add
1326 * lr to the temp set. It is safe to do this locally, but note that
1327 * lr is used explicitly elsewhere in the code generator and cannot
1328 * normally be used as a general temp register.
1329 */
1330 oatMarkTemp(cUnit, rLR); // Add lr to the temp pool
1331 oatFreeTemp(cUnit, rLR); // and make it available
1332#endif
1333 rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
1334 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1335 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1336 // The longs may overlap - use intermediate temp if so
1337 if (rlResult.lowReg == rlSrc1.highReg) {
1338 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001339 opRegCopy(cUnit, tReg, rlSrc1.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001340 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1341 rlSrc2.lowReg);
1342 opRegRegReg(cUnit, secondOp, rlResult.highReg, tReg,
1343 rlSrc2.highReg);
1344 oatFreeTemp(cUnit, tReg);
1345 } else {
1346 opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
1347 rlSrc2.lowReg);
1348 opRegRegReg(cUnit, secondOp, rlResult.highReg, rlSrc1.highReg,
1349 rlSrc2.highReg);
1350 }
1351 /*
1352 * NOTE: If rlDest refers to a frame variable in a large frame, the
1353 * following storeValueWide might need to allocate a temp register.
1354 * To further work around the lack of a spill capability, explicitly
1355 * free any temps from rlSrc1 & rlSrc2 that aren't still live in rlResult.
1356 * Remove when spill is functional.
1357 */
1358 freeRegLocTemps(cUnit, rlResult, rlSrc1);
1359 freeRegLocTemps(cUnit, rlResult, rlSrc2);
1360 storeValueWide(cUnit, rlDest, rlResult);
1361#if defined(TARGET_ARM)
1362 oatClobber(cUnit, rLR);
1363 oatUnmarkTemp(cUnit, rLR); // Remove lr from the temp pool
1364#endif
1365}
1366
1367
1368bool genShiftOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1369 RegLocation rlSrc1, RegLocation rlShift)
1370{
1371 int funcOffset;
1372
1373 switch( mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001374 case Instruction::SHL_LONG:
1375 case Instruction::SHL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001376 funcOffset = OFFSETOF_MEMBER(Thread, pShlLong);
1377 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001378 case Instruction::SHR_LONG:
1379 case Instruction::SHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001380 funcOffset = OFFSETOF_MEMBER(Thread, pShrLong);
1381 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001382 case Instruction::USHR_LONG:
1383 case Instruction::USHR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001384 funcOffset = OFFSETOF_MEMBER(Thread, pUshrLong);
1385 break;
1386 default:
1387 LOG(FATAL) << "Unexpected case";
1388 return true;
1389 }
1390 oatFlushAllRegs(cUnit); /* Send everything to home location */
1391 int rTgt = loadHelper(cUnit, funcOffset);
1392 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1393 loadValueDirect(cUnit, rlShift, rARG2);
1394 callRuntimeHelper(cUnit, rTgt);
1395 RegLocation rlResult = oatGetReturnWide(cUnit);
1396 storeValueWide(cUnit, rlDest, rlResult);
1397 return false;
1398}
1399
1400
1401bool genArithOpInt(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1402 RegLocation rlSrc1, RegLocation rlSrc2)
1403{
1404 OpKind op = kOpBkpt;
1405 bool callOut = false;
1406 bool checkZero = false;
1407 bool unary = false;
1408 int retReg = rRET0;
1409 int funcOffset;
1410 RegLocation rlResult;
1411 bool shiftOp = false;
1412
1413 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001414 case Instruction::NEG_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001415 op = kOpNeg;
1416 unary = true;
1417 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001418 case Instruction::NOT_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08001419 op = kOpMvn;
1420 unary = true;
1421 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001422 case Instruction::ADD_INT:
1423 case Instruction::ADD_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001424 op = kOpAdd;
1425 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001426 case Instruction::SUB_INT:
1427 case Instruction::SUB_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001428 op = kOpSub;
1429 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001430 case Instruction::MUL_INT:
1431 case Instruction::MUL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001432 op = kOpMul;
1433 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001434 case Instruction::DIV_INT:
1435 case Instruction::DIV_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001436 callOut = true;
1437 checkZero = true;
1438 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1439 retReg = rRET0;
1440 break;
buzbee5de34942012-03-01 14:51:57 -08001441 /* NOTE: returns in rARG1 */
Elliott Hughesadb8c672012-03-06 16:49:32 -08001442 case Instruction::REM_INT:
1443 case Instruction::REM_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001444 callOut = true;
1445 checkZero = true;
1446 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1447 retReg = rRET1;
1448 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001449 case Instruction::AND_INT:
1450 case Instruction::AND_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001451 op = kOpAnd;
1452 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001453 case Instruction::OR_INT:
1454 case Instruction::OR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001455 op = kOpOr;
1456 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001457 case Instruction::XOR_INT:
1458 case Instruction::XOR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001459 op = kOpXor;
1460 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001461 case Instruction::SHL_INT:
1462 case Instruction::SHL_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001463 shiftOp = true;
1464 op = kOpLsl;
1465 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001466 case Instruction::SHR_INT:
1467 case Instruction::SHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001468 shiftOp = true;
1469 op = kOpAsr;
1470 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001471 case Instruction::USHR_INT:
1472 case Instruction::USHR_INT_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001473 shiftOp = true;
1474 op = kOpLsr;
1475 break;
1476 default:
1477 LOG(FATAL) << "Invalid word arith op: " <<
1478 (int)mir->dalvikInsn.opcode;
1479 }
1480 if (!callOut) {
1481 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1482 if (unary) {
1483 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1484 opRegReg(cUnit, op, rlResult.lowReg,
1485 rlSrc1.lowReg);
1486 } else {
1487 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1488 if (shiftOp) {
1489 int tReg = oatAllocTemp(cUnit);
1490 opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
1491 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1492 opRegRegReg(cUnit, op, rlResult.lowReg,
1493 rlSrc1.lowReg, tReg);
1494 oatFreeTemp(cUnit, tReg);
1495 } else {
1496 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1497 opRegRegReg(cUnit, op, rlResult.lowReg,
1498 rlSrc1.lowReg, rlSrc2.lowReg);
1499 }
1500 }
1501 storeValue(cUnit, rlDest, rlResult);
1502 } else {
1503 RegLocation rlResult;
1504 oatFlushAllRegs(cUnit); /* Send everything to home location */
1505 loadValueDirectFixed(cUnit, rlSrc2, rRET1);
1506 int rTgt = loadHelper(cUnit, funcOffset);
1507 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1508 if (checkZero) {
1509 genImmedCheck(cUnit, kCondEq, rARG1, 0, mir, kThrowDivZero);
1510 }
1511 callRuntimeHelper(cUnit, rTgt);
1512 if (retReg == rRET0)
1513 rlResult = oatGetReturn(cUnit);
1514 else
1515 rlResult = oatGetReturnAlt(cUnit);
1516 storeValue(cUnit, rlDest, rlResult);
1517 }
1518 return false;
1519}
1520
1521/*
1522 * The following are the first-level codegen routines that analyze the format
1523 * of each bytecode then either dispatch special purpose codegen routines
1524 * or produce corresponding Thumb instructions directly.
1525 */
1526
1527bool isPowerOfTwo(int x)
1528{
1529 return (x & (x - 1)) == 0;
1530}
1531
1532// Returns true if no more than two bits are set in 'x'.
1533bool isPopCountLE2(unsigned int x)
1534{
1535 x &= x - 1;
1536 return (x & (x - 1)) == 0;
1537}
1538
1539// Returns the index of the lowest set bit in 'x'.
1540int lowestSetBit(unsigned int x) {
1541 int bit_posn = 0;
1542 while ((x & 0xf) == 0) {
1543 bit_posn += 4;
1544 x >>= 4;
1545 }
1546 while ((x & 1) == 0) {
1547 bit_posn++;
1548 x >>= 1;
1549 }
1550 return bit_posn;
1551}
1552
1553// Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
1554// and store the result in 'rlDest'.
Elliott Hughesadb8c672012-03-06 16:49:32 -08001555bool handleEasyDivide(CompilationUnit* cUnit, Instruction::Code dalvikOpcode,
buzbee31a4a6f2012-02-28 15:36:15 -08001556 RegLocation rlSrc, RegLocation rlDest, int lit)
1557{
1558 if (lit < 2 || !isPowerOfTwo(lit)) {
1559 return false;
1560 }
1561 int k = lowestSetBit(lit);
1562 if (k >= 30) {
1563 // Avoid special cases.
1564 return false;
1565 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08001566 bool div = (dalvikOpcode == Instruction::DIV_INT_LIT8 ||
1567 dalvikOpcode == Instruction::DIV_INT_LIT16);
buzbee31a4a6f2012-02-28 15:36:15 -08001568 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1569 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1570 if (div) {
1571 int tReg = oatAllocTemp(cUnit);
1572 if (lit == 2) {
1573 // Division by 2 is by far the most common division by constant.
1574 opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
1575 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1576 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1577 } else {
1578 opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
1579 opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
1580 opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
1581 opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
1582 }
1583 } else {
1584 int cReg = oatAllocTemp(cUnit);
1585 loadConstant(cUnit, cReg, lit - 1);
1586 int tReg1 = oatAllocTemp(cUnit);
1587 int tReg2 = oatAllocTemp(cUnit);
1588 if (lit == 2) {
1589 opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
1590 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1591 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1592 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1593 } else {
1594 opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
1595 opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
1596 opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
1597 opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
1598 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
1599 }
1600 }
1601 storeValue(cUnit, rlDest, rlResult);
1602 return true;
1603}
1604
1605void genMultiplyByTwoBitMultiplier(CompilationUnit* cUnit, RegLocation rlSrc,
1606 RegLocation rlResult, int lit,
1607 int firstBit, int secondBit)
1608{
buzbee0398c422012-03-02 15:22:47 -08001609#if defined(TARGET_ARM)
buzbee31a4a6f2012-02-28 15:36:15 -08001610 opRegRegRegShift(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, rlSrc.lowReg,
1611 encodeShift(kArmLsl, secondBit - firstBit));
buzbee0398c422012-03-02 15:22:47 -08001612#else
1613 int tReg = oatAllocTemp(cUnit);
1614 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, secondBit - firstBit);
1615 opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, tReg);
1616 oatFreeTemp(cUnit, tReg);
buzbee5de34942012-03-01 14:51:57 -08001617#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001618 if (firstBit != 0) {
1619 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlResult.lowReg, firstBit);
1620 }
1621}
1622
1623// Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
1624// and store the result in 'rlDest'.
1625bool handleEasyMultiply(CompilationUnit* cUnit, RegLocation rlSrc,
1626 RegLocation rlDest, int lit)
1627{
1628 // Can we simplify this multiplication?
1629 bool powerOfTwo = false;
1630 bool popCountLE2 = false;
1631 bool powerOfTwoMinusOne = false;
1632 if (lit < 2) {
1633 // Avoid special cases.
1634 return false;
1635 } else if (isPowerOfTwo(lit)) {
1636 powerOfTwo = true;
1637 } else if (isPopCountLE2(lit)) {
1638 popCountLE2 = true;
1639 } else if (isPowerOfTwo(lit + 1)) {
1640 powerOfTwoMinusOne = true;
1641 } else {
1642 return false;
1643 }
1644 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1645 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1646 if (powerOfTwo) {
1647 // Shift.
1648 opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
1649 lowestSetBit(lit));
1650 } else if (popCountLE2) {
1651 // Shift and add and shift.
1652 int firstBit = lowestSetBit(lit);
1653 int secondBit = lowestSetBit(lit ^ (1 << firstBit));
1654 genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
1655 firstBit, secondBit);
1656 } else {
1657 // Reverse subtract: (src << (shift + 1)) - src.
1658 DCHECK(powerOfTwoMinusOne);
1659 // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
1660 int tReg = oatAllocTemp(cUnit);
1661 opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
1662 opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
1663 }
1664 storeValue(cUnit, rlDest, rlResult);
1665 return true;
1666}
1667
1668bool genArithOpIntLit(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1669 RegLocation rlSrc, int lit)
1670{
Elliott Hughesadb8c672012-03-06 16:49:32 -08001671 Instruction::Code dalvikOpcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08001672 RegLocation rlResult;
1673 OpKind op = (OpKind)0; /* Make gcc happy */
1674 int shiftOp = false;
1675 bool isDiv = false;
1676 int funcOffset;
1677 int rTgt;
1678
1679 switch (dalvikOpcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001680 case Instruction::RSUB_INT_LIT8:
1681 case Instruction::RSUB_INT: {
buzbee31a4a6f2012-02-28 15:36:15 -08001682 int tReg;
1683 //TUNING: add support for use of Arm rsub op
1684 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1685 tReg = oatAllocTemp(cUnit);
1686 loadConstant(cUnit, tReg, lit);
1687 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1688 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1689 tReg, rlSrc.lowReg);
1690 storeValue(cUnit, rlDest, rlResult);
1691 return false;
1692 break;
1693 }
1694
Elliott Hughesadb8c672012-03-06 16:49:32 -08001695 case Instruction::ADD_INT_LIT8:
1696 case Instruction::ADD_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001697 op = kOpAdd;
1698 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001699 case Instruction::MUL_INT_LIT8:
1700 case Instruction::MUL_INT_LIT16: {
buzbee31a4a6f2012-02-28 15:36:15 -08001701 if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
1702 return false;
1703 }
1704 op = kOpMul;
1705 break;
1706 }
Elliott Hughesadb8c672012-03-06 16:49:32 -08001707 case Instruction::AND_INT_LIT8:
1708 case Instruction::AND_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001709 op = kOpAnd;
1710 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001711 case Instruction::OR_INT_LIT8:
1712 case Instruction::OR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001713 op = kOpOr;
1714 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001715 case Instruction::XOR_INT_LIT8:
1716 case Instruction::XOR_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001717 op = kOpXor;
1718 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001719 case Instruction::SHL_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001720 lit &= 31;
1721 shiftOp = true;
1722 op = kOpLsl;
1723 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001724 case Instruction::SHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001725 lit &= 31;
1726 shiftOp = true;
1727 op = kOpAsr;
1728 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001729 case Instruction::USHR_INT_LIT8:
buzbee31a4a6f2012-02-28 15:36:15 -08001730 lit &= 31;
1731 shiftOp = true;
1732 op = kOpLsr;
1733 break;
1734
Elliott Hughesadb8c672012-03-06 16:49:32 -08001735 case Instruction::DIV_INT_LIT8:
1736 case Instruction::DIV_INT_LIT16:
1737 case Instruction::REM_INT_LIT8:
1738 case Instruction::REM_INT_LIT16:
buzbee31a4a6f2012-02-28 15:36:15 -08001739 if (lit == 0) {
1740 genImmedCheck(cUnit, kCondAl, 0, 0, mir, kThrowDivZero);
1741 return false;
1742 }
1743 if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
1744 return false;
1745 }
1746 oatFlushAllRegs(cUnit); /* Everything to home location */
1747 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1748 oatClobber(cUnit, rARG0);
Elliott Hughesadb8c672012-03-06 16:49:32 -08001749 if ((dalvikOpcode == Instruction::DIV_INT_LIT8) ||
1750 (dalvikOpcode == Instruction::DIV_INT_LIT16)) {
buzbee31a4a6f2012-02-28 15:36:15 -08001751 funcOffset = OFFSETOF_MEMBER(Thread, pIdiv);
1752 isDiv = true;
1753 } else {
1754 funcOffset = OFFSETOF_MEMBER(Thread, pIdivmod);
1755 isDiv = false;
1756 }
1757 rTgt = loadHelper(cUnit, funcOffset);
1758 loadConstant(cUnit, rARG1, lit);
1759 callRuntimeHelper(cUnit, rTgt);
1760 if (isDiv)
1761 rlResult = oatGetReturn(cUnit);
1762 else
1763 rlResult = oatGetReturnAlt(cUnit);
1764 storeValue(cUnit, rlDest, rlResult);
1765 return false;
1766 break;
1767 default:
1768 return true;
1769 }
1770 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
1771 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1772 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
1773 if (shiftOp && (lit == 0)) {
buzbee82488f52012-03-02 08:20:26 -08001774 opRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001775 } else {
1776 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
1777 }
1778 storeValue(cUnit, rlDest, rlResult);
1779 return false;
1780}
1781
1782bool genArithOpLong(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
1783 RegLocation rlSrc1, RegLocation rlSrc2)
1784{
buzbeea7678db2012-03-05 15:35:46 -08001785#if defined(TARGET_X86)
1786 UNIMPLEMENTED(WARNING) << "genArithOpLong";
1787 return false;
1788#else
buzbee31a4a6f2012-02-28 15:36:15 -08001789 RegLocation rlResult;
1790 OpKind firstOp = kOpBkpt;
1791 OpKind secondOp = kOpBkpt;
1792 bool callOut = false;
1793 bool checkZero = false;
1794 int funcOffset;
1795 int retReg = rRET0;
1796
1797 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001798 case Instruction::NOT_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08001799 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1800 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1801 // Check for destructive overlap
1802 if (rlResult.lowReg == rlSrc2.highReg) {
1803 int tReg = oatAllocTemp(cUnit);
buzbee82488f52012-03-02 08:20:26 -08001804 opRegCopy(cUnit, tReg, rlSrc2.highReg);
buzbee31a4a6f2012-02-28 15:36:15 -08001805 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1806 opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
1807 oatFreeTemp(cUnit, tReg);
1808 } else {
1809 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1810 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1811 }
1812 storeValueWide(cUnit, rlDest, rlResult);
1813 return false;
1814 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001815 case Instruction::ADD_LONG:
1816 case Instruction::ADD_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08001817#if defined(TARGET_MIPS)
1818 return genAddLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1819#else
buzbee31a4a6f2012-02-28 15:36:15 -08001820 firstOp = kOpAdd;
1821 secondOp = kOpAdc;
1822 break;
buzbeec5159d52012-03-03 11:48:39 -08001823#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08001824 case Instruction::SUB_LONG:
1825 case Instruction::SUB_LONG_2ADDR:
buzbeec5159d52012-03-03 11:48:39 -08001826#if defined(TARGET_MIPS)
1827 return genSubLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
1828#else
buzbee31a4a6f2012-02-28 15:36:15 -08001829 firstOp = kOpSub;
1830 secondOp = kOpSbc;
1831 break;
buzbeec5159d52012-03-03 11:48:39 -08001832#endif
Elliott Hughesadb8c672012-03-06 16:49:32 -08001833 case Instruction::MUL_LONG:
1834 case Instruction::MUL_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001835 callOut = true;
1836 retReg = rRET0;
1837 funcOffset = OFFSETOF_MEMBER(Thread, pLmul);
1838 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001839 case Instruction::DIV_LONG:
1840 case Instruction::DIV_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001841 callOut = true;
1842 checkZero = true;
1843 retReg = rRET0;
1844 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1845 break;
1846 /* NOTE - result is in rARG2/rARG3 instead of rRET0/rRET1 */
1847 // FIXME: is true, or could be made true, or other targets?
Elliott Hughesadb8c672012-03-06 16:49:32 -08001848 case Instruction::REM_LONG:
1849 case Instruction::REM_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001850 callOut = true;
1851 checkZero = true;
1852 funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
1853 retReg = rARG2;
1854 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001855 case Instruction::AND_LONG_2ADDR:
1856 case Instruction::AND_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08001857 firstOp = kOpAnd;
1858 secondOp = kOpAnd;
1859 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001860 case Instruction::OR_LONG:
1861 case Instruction::OR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001862 firstOp = kOpOr;
1863 secondOp = kOpOr;
1864 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001865 case Instruction::XOR_LONG:
1866 case Instruction::XOR_LONG_2ADDR:
buzbee31a4a6f2012-02-28 15:36:15 -08001867 firstOp = kOpXor;
1868 secondOp = kOpXor;
1869 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001870 case Instruction::NEG_LONG: {
buzbeec5159d52012-03-03 11:48:39 -08001871 return genNegLong(cUnit, mir, rlDest, rlSrc2);
buzbee31a4a6f2012-02-28 15:36:15 -08001872 }
1873 default:
1874 LOG(FATAL) << "Invalid long arith op";
1875 }
1876 if (!callOut) {
1877 genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
1878 } else {
1879 int rTgt;
1880 oatFlushAllRegs(cUnit); /* Send everything to home location */
1881 if (checkZero) {
1882 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
1883 rTgt = loadHelper(cUnit, funcOffset);
1884 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1885 int tReg = oatAllocTemp(cUnit);
1886#if defined(TARGET_ARM)
1887 newLIR4(cUnit, kThumb2OrrRRRs, tReg, rARG2, rARG3, 0);
1888 oatFreeTemp(cUnit, tReg);
1889 genCheck(cUnit, kCondEq, mir, kThrowDivZero);
1890#else
1891 opRegRegReg(cUnit, kOpOr, tReg, rARG2, rARG3);
buzbee5de34942012-03-01 14:51:57 -08001892 genImmedCheck(cUnit, kCondEq, tReg, 0, mir, kThrowDivZero);
buzbee31a4a6f2012-02-28 15:36:15 -08001893 oatFreeTemp(cUnit, tReg);
1894#endif
1895 } else {
1896 rTgt = loadHelper(cUnit, funcOffset);
1897 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
1898 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
1899 }
1900 callRuntimeHelper(cUnit, rTgt);
1901 // Adjust return regs in to handle case of rem returning rARG2/rARG3
1902 if (retReg == rRET0)
1903 rlResult = oatGetReturnWide(cUnit);
1904 else
1905 rlResult = oatGetReturnWideAlt(cUnit);
1906 storeValueWide(cUnit, rlDest, rlResult);
1907 }
1908 return false;
buzbeea7678db2012-03-05 15:35:46 -08001909#endif
buzbee31a4a6f2012-02-28 15:36:15 -08001910}
1911
1912bool genConversionCall(CompilationUnit* cUnit, MIR* mir, int funcOffset,
1913 int srcSize, int tgtSize)
1914{
1915 /*
1916 * Don't optimize the register usage since it calls out to support
1917 * functions
1918 */
1919 RegLocation rlSrc;
1920 RegLocation rlDest;
1921 oatFlushAllRegs(cUnit); /* Send everything to home location */
1922 int rTgt = loadHelper(cUnit, funcOffset);
1923 if (srcSize == 1) {
1924 rlSrc = oatGetSrc(cUnit, mir, 0);
1925 loadValueDirectFixed(cUnit, rlSrc, rARG0);
1926 } else {
1927 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
1928 loadValueDirectWideFixed(cUnit, rlSrc, rARG0, rARG1);
1929 }
1930 callRuntimeHelper(cUnit, rTgt);
1931 if (tgtSize == 1) {
1932 RegLocation rlResult;
1933 rlDest = oatGetDest(cUnit, mir, 0);
1934 rlResult = oatGetReturn(cUnit);
1935 storeValue(cUnit, rlDest, rlResult);
1936 } else {
1937 RegLocation rlResult;
1938 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1939 rlResult = oatGetReturnWide(cUnit);
1940 storeValueWide(cUnit, rlDest, rlResult);
1941 }
1942 return false;
1943}
1944
1945void genNegFloat(CompilationUnit* cUnit, RegLocation rlDest, RegLocation rlSrc);
1946bool genArithOpFloatPortable(CompilationUnit* cUnit, MIR* mir,
1947 RegLocation rlDest, RegLocation rlSrc1,
1948 RegLocation rlSrc2)
1949{
1950 RegLocation rlResult;
1951 int funcOffset;
1952
1953 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08001954 case Instruction::ADD_FLOAT_2ADDR:
1955 case Instruction::ADD_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08001956 funcOffset = OFFSETOF_MEMBER(Thread, pFadd);
1957 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001958 case Instruction::SUB_FLOAT_2ADDR:
1959 case Instruction::SUB_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08001960 funcOffset = OFFSETOF_MEMBER(Thread, pFsub);
1961 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001962 case Instruction::DIV_FLOAT_2ADDR:
1963 case Instruction::DIV_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08001964 funcOffset = OFFSETOF_MEMBER(Thread, pFdiv);
1965 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001966 case Instruction::MUL_FLOAT_2ADDR:
1967 case Instruction::MUL_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08001968 funcOffset = OFFSETOF_MEMBER(Thread, pFmul);
1969 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001970 case Instruction::REM_FLOAT_2ADDR:
1971 case Instruction::REM_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08001972 funcOffset = OFFSETOF_MEMBER(Thread, pFmodf);
1973 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08001974 case Instruction::NEG_FLOAT: {
buzbee31a4a6f2012-02-28 15:36:15 -08001975 genNegFloat(cUnit, rlDest, rlSrc1);
1976 return false;
1977 }
1978 default:
1979 return true;
1980 }
1981 oatFlushAllRegs(cUnit); /* Send everything to home location */
1982 int rTgt = loadHelper(cUnit, funcOffset);
1983 loadValueDirectFixed(cUnit, rlSrc1, rARG0);
1984 loadValueDirectFixed(cUnit, rlSrc2, rARG1);
1985 callRuntimeHelper(cUnit, rTgt);
1986 rlResult = oatGetReturn(cUnit);
1987 storeValue(cUnit, rlDest, rlResult);
1988 return false;
1989}
1990
1991void genNegDouble(CompilationUnit* cUnit, RegLocation rlDst, RegLocation rlSrc);
1992bool genArithOpDoublePortable(CompilationUnit* cUnit, MIR* mir,
1993 RegLocation rlDest, RegLocation rlSrc1,
1994 RegLocation rlSrc2)
1995{
buzbeea7678db2012-03-05 15:35:46 -08001996#if defined(TARGET_X86)
1997//NOTE: probably don't need the portable versions for x86
1998 UNIMPLEMENTED(WARNING) << "genArithOpDoublePortable";
1999 return false;
2000#else
buzbee31a4a6f2012-02-28 15:36:15 -08002001 RegLocation rlResult;
2002 int funcOffset;
2003
2004 switch (mir->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002005 case Instruction::ADD_DOUBLE_2ADDR:
2006 case Instruction::ADD_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002007 funcOffset = OFFSETOF_MEMBER(Thread, pDadd);
2008 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002009 case Instruction::SUB_DOUBLE_2ADDR:
2010 case Instruction::SUB_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002011 funcOffset = OFFSETOF_MEMBER(Thread, pDsub);
2012 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002013 case Instruction::DIV_DOUBLE_2ADDR:
2014 case Instruction::DIV_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002015 funcOffset = OFFSETOF_MEMBER(Thread, pDdiv);
2016 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002017 case Instruction::MUL_DOUBLE_2ADDR:
2018 case Instruction::MUL_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002019 funcOffset = OFFSETOF_MEMBER(Thread, pDmul);
2020 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002021 case Instruction::REM_DOUBLE_2ADDR:
2022 case Instruction::REM_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002023 funcOffset = OFFSETOF_MEMBER(Thread, pFmod);
2024 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -08002025 case Instruction::NEG_DOUBLE: {
buzbee31a4a6f2012-02-28 15:36:15 -08002026 genNegDouble(cUnit, rlDest, rlSrc1);
2027 return false;
2028 }
2029 default:
2030 return true;
2031 }
2032 oatFlushAllRegs(cUnit); /* Send everything to home location */
2033 int rTgt = loadHelper(cUnit, funcOffset);
2034 loadValueDirectWideFixed(cUnit, rlSrc1, rARG0, rARG1);
2035 loadValueDirectWideFixed(cUnit, rlSrc2, rARG2, rARG3);
2036 callRuntimeHelper(cUnit, rTgt);
2037 rlResult = oatGetReturnWide(cUnit);
2038 storeValueWide(cUnit, rlDest, rlResult);
2039 return false;
buzbeea7678db2012-03-05 15:35:46 -08002040#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002041}
2042
2043bool genConversionPortable(CompilationUnit* cUnit, MIR* mir)
2044{
Elliott Hughesadb8c672012-03-06 16:49:32 -08002045 Instruction::Code opcode = mir->dalvikInsn.opcode;
buzbee31a4a6f2012-02-28 15:36:15 -08002046
2047 switch (opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -08002048 case Instruction::INT_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002049 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2f),
2050 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002051 case Instruction::FLOAT_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002052 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2iz),
2053 1, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002054 case Instruction::DOUBLE_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002055 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2f),
2056 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002057 case Instruction::FLOAT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002058 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pF2d),
2059 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002060 case Instruction::INT_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002061 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pI2d),
2062 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002063 case Instruction::DOUBLE_TO_INT:
buzbee31a4a6f2012-02-28 15:36:15 -08002064 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pD2iz),
2065 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002066 case Instruction::FLOAT_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002067 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2068 pF2l), 1, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002069 case Instruction::LONG_TO_FLOAT:
buzbee31a4a6f2012-02-28 15:36:15 -08002070 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
2071 2, 1);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002072 case Instruction::DOUBLE_TO_LONG:
buzbee31a4a6f2012-02-28 15:36:15 -08002073 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
2074 pD2l), 2, 2);
Elliott Hughesadb8c672012-03-06 16:49:32 -08002075 case Instruction::LONG_TO_DOUBLE:
buzbee31a4a6f2012-02-28 15:36:15 -08002076 return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
2077 2, 2);
2078 default:
2079 return true;
2080 }
2081 return false;
2082}
2083
2084/*
2085 * Generate callout to updateDebugger. Note that we're overloading
2086 * the use of rSUSPEND here. When the debugger is active, this
2087 * register holds the address of the update function. So, if it's
2088 * non-null, we call out to it.
2089 *
2090 * Note also that rRET0 and rRET1 must be preserved across this
2091 * code. This must be handled by the stub.
2092 */
2093void genDebuggerUpdate(CompilationUnit* cUnit, int32_t offset)
2094{
buzbeea7678db2012-03-05 15:35:46 -08002095#if defined(TARGET_X86)
2096 UNIMPLEMENTED(WARNING);
2097#else
buzbee31a4a6f2012-02-28 15:36:15 -08002098 // Following DCHECK verifies that dPC is in range of single load immediate
2099 DCHECK((offset == DEBUGGER_METHOD_ENTRY) ||
2100 (offset == DEBUGGER_METHOD_EXIT) || ((offset & 0xffff) == offset));
2101 oatClobberCalleeSave(cUnit);
2102#if defined(TARGET_ARM)
2103 opRegImm(cUnit, kOpCmp, rSUSPEND, 0);
buzbee82488f52012-03-02 08:20:26 -08002104 opIT(cUnit, kArmCondNe, "T");
buzbee31a4a6f2012-02-28 15:36:15 -08002105 loadConstant(cUnit, rARG2, offset); // arg2 <- Entry code
2106 opReg(cUnit, kOpBlx, rSUSPEND);
2107#else
buzbee82488f52012-03-02 08:20:26 -08002108 LIR* branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002109 loadConstant(cUnit, rARG2, offset);
2110 opReg(cUnit, kOpBlx, rSUSPEND);
2111 LIR* target = newLIR0(cUnit, kPseudoTargetLabel);
buzbee31a4a6f2012-02-28 15:36:15 -08002112 branch->target = (LIR*)target;
2113#endif
2114 oatFreeTemp(cUnit, rARG2);
buzbeea7678db2012-03-05 15:35:46 -08002115#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002116}
2117
2118/* Check if we need to check for pending suspend request */
2119void genSuspendTest(CompilationUnit* cUnit, MIR* mir)
2120{
buzbeea7678db2012-03-05 15:35:46 -08002121#if defined(TARGET_X86)
2122 UNIMPLEMENTED(WARNING) << "genSuspendTest";
2123#else
buzbee31a4a6f2012-02-28 15:36:15 -08002124 if (NO_SUSPEND || (mir->optimizationFlags & MIR_IGNORE_SUSPEND_CHECK)) {
2125 return;
2126 }
2127 oatFlushAllRegs(cUnit);
buzbee31a4a6f2012-02-28 15:36:15 -08002128 if (cUnit->genDebugger) {
2129 // If generating code for the debugger, always check for suspension
buzbee86a4bce2012-03-06 18:15:00 -08002130 int rTgt = loadHelper(cUnit, OFFSETOF_MEMBER(Thread,
2131 pTestSuspendFromCode));
2132 opReg(cUnit, kOpBlx, rTgt);
2133 // Refresh rSUSPEND
2134 loadWordDisp(cUnit, rSELF,
2135 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode),
2136 rSUSPEND);
buzbee31a4a6f2012-02-28 15:36:15 -08002137 } else {
buzbee86a4bce2012-03-06 18:15:00 -08002138 LIR* branch;
buzbee31a4a6f2012-02-28 15:36:15 -08002139#if defined(TARGET_ARM)
2140 // In non-debug case, only check periodically
2141 newLIR2(cUnit, kThumbSubRI8, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002142 branch = opCondBranch(cUnit, kCondEq, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002143#else
2144 opRegImm(cUnit, kOpSub, rSUSPEND, 1);
buzbee82488f52012-03-02 08:20:26 -08002145 branch = opCmpImmBranch(cUnit, kCondEq, rSUSPEND, 0, NULL);
buzbee31a4a6f2012-02-28 15:36:15 -08002146#endif
buzbee86a4bce2012-03-06 18:15:00 -08002147 LIR* retLab = newLIR0(cUnit, kPseudoTargetLabel);
2148 LIR* target = rawLIR(cUnit, cUnit->currentDalvikOffset,
2149 kPseudoSuspendTarget, (intptr_t)retLab, mir->offset);
2150 branch->target = (LIR*)target;
2151 oatInsertGrowableList(cUnit, &cUnit->suspendLaunchpads, (intptr_t)target);
buzbee31a4a6f2012-02-28 15:36:15 -08002152 }
buzbeea7678db2012-03-05 15:35:46 -08002153#endif
buzbee31a4a6f2012-02-28 15:36:15 -08002154}
2155
2156} // namespace art