blob: c512e8bd90df57eeccc5dce596f0c7b057a8a4e0 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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
Ian Rogers6d4d9fc2011-11-30 16:24:48 -080017#include "object_utils.h"
18
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080019namespace art {
20
buzbeece302932011-10-04 14:32:18 -070021#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
22 (1 << kDebugDisplayMissingTargets))
Elliott Hughes1240dad2011-09-09 16:24:50 -070023
buzbee67bc2362011-10-11 18:08:40 -070024STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, INVALID_REG,
25 INVALID_REG, INVALID_SREG};
buzbee6181f792011-09-29 11:14:04 -070026
27/* Mark register usage state and return long retloc */
28STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
29{
30 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
31 oatLockTemp(cUnit, res.lowReg);
32 oatLockTemp(cUnit, res.highReg);
33 oatMarkPair(cUnit, res.lowReg, res.highReg);
34 return res;
35}
36
37STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
38{
39 RegLocation res = LOC_DALVIK_RETURN_VAL;
40 oatLockTemp(cUnit, res.lowReg);
41 return res;
42}
buzbee67bf8852011-08-17 17:51:35 -070043
buzbeedfd3d702011-08-28 12:56:51 -070044/*
45 * Let helper function take care of everything. Will call
46 * Array::AllocFromCode(type_idx, method, count);
47 * Note: AllocFromCode will handle checks for errNegativeArraySize.
48 */
buzbeeed3e9302011-09-23 17:34:19 -070049STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -070050 RegLocation rlSrc)
51{
buzbeedfd3d702011-08-28 12:56:51 -070052 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -070053 uint32_t type_idx = mir->dalvikInsn.vC;
Ian Rogersa3760aa2011-11-14 14:32:37 -080054 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
55 cUnit->dex_cache,
56 *cUnit->dex_file,
57 type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -070058 loadWordDisp(cUnit, rSELF,
59 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
60 } else {
Ian Rogers28ad40d2011-10-27 15:19:26 -070061 loadWordDisp(cUnit, rSELF,
Ian Rogers0eb7d7e2012-01-31 21:12:32 -080062 OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
Ian Rogers28ad40d2011-10-27 15:19:26 -070063 }
buzbeedfd3d702011-08-28 12:56:51 -070064 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -070065 loadConstant(cUnit, r0, type_idx); // arg0 <- type_id
buzbeedfd3d702011-08-28 12:56:51 -070066 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070067 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070068 RegLocation rlResult = oatGetReturn(cUnit);
69 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070070}
71
72/*
73 * Similar to genNewArray, but with post-allocation initialization.
74 * Verifier guarantees we're dealing with an array class. Current
75 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
76 * Current code also throws internal unimp if not 'L', '[' or 'I'.
77 */
buzbeeed3e9302011-09-23 17:34:19 -070078STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070079{
80 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070081 int elems = dInsn->vA;
82 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070083 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers0eb7d7e2012-01-31 21:12:32 -080084 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
85 cUnit->dex_cache,
86 *cUnit->dex_file,
87 typeId)) {
88 loadWordDisp(cUnit, rSELF,
89 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
90 } else {
91 loadWordDisp(cUnit, rSELF,
92 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
Ian Rogers28ad40d2011-10-27 15:19:26 -070093 }
buzbeedfd3d702011-08-28 12:56:51 -070094 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
95 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
96 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070097 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070098 /*
buzbeedfd3d702011-08-28 12:56:51 -070099 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
100 * return region. Because AllocFromCode placed the new array
101 * in r0, we'll just lock it into place. When debugger support is
102 * added, it may be necessary to additionally copy all return
103 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -0700104 */
buzbee67bf8852011-08-17 17:51:35 -0700105 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -0700106
buzbee67bf8852011-08-17 17:51:35 -0700107 // Having a range of 0 is legal
108 if (isRange && (dInsn->vA > 0)) {
109 /*
110 * Bit of ugliness here. We're going generate a mem copy loop
111 * on the register range, but it is possible that some regs
112 * in the range have been promoted. This is unlikely, but
113 * before generating the copy, we'll just force a flush
114 * of any regs in the source range that have been promoted to
115 * home location.
116 */
117 for (unsigned int i = 0; i < dInsn->vA; i++) {
118 RegLocation loc = oatUpdateLoc(cUnit,
119 oatGetSrc(cUnit, mir, i));
120 if (loc.location == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -0700121 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
122 loc.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700123 }
124 }
125 /*
126 * TUNING note: generated code here could be much improved, but
127 * this is an uncommon operation and isn't especially performance
128 * critical.
129 */
130 int rSrc = oatAllocTemp(cUnit);
131 int rDst = oatAllocTemp(cUnit);
132 int rIdx = oatAllocTemp(cUnit);
133 int rVal = rLR; // Using a lot of temps, rLR is known free here
134 // Set up source pointer
135 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
buzbee67bc2362011-10-11 18:08:40 -0700136 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
137 oatSRegOffset(cUnit, rlFirst.sRegLow));
buzbee67bf8852011-08-17 17:51:35 -0700138 // Set up the target pointer
139 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700140 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700141 // Set up the loop counter (known to be > 0)
buzbee31813452011-10-16 14:33:08 -0700142 loadConstant(cUnit, rIdx, dInsn->vA - 1);
buzbee67bf8852011-08-17 17:51:35 -0700143 // Generate the copy loop. Going backwards for convenience
144 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
145 target->defMask = ENCODE_ALL;
146 // Copy next element
147 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
148 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
149 // Use setflags encoding here
150 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee31813452011-10-16 14:33:08 -0700151 ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
buzbee67bf8852011-08-17 17:51:35 -0700152 branch->generic.target = (LIR*)target;
153 } else if (!isRange) {
154 // TUNING: interleave
155 for (unsigned int i = 0; i < dInsn->vA; i++) {
156 RegLocation rlArg = loadValue(cUnit,
157 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700158 storeBaseDisp(cUnit, r0,
159 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700160 i * 4, rlArg.lowReg, kWord);
161 // If the loadValue caused a temp to be allocated, free it
162 if (oatIsTemp(cUnit, rlArg.lowReg)) {
163 oatFreeTemp(cUnit, rlArg.lowReg);
164 }
165 }
166 }
167}
168
Ian Rogers1bddec32012-02-04 12:27:34 -0800169STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
170 bool isLongOrDouble, bool isObject)
buzbee67bf8852011-08-17 17:51:35 -0700171{
Ian Rogers1bddec32012-02-04 12:27:34 -0800172 int fieldOffset;
173 int ssbIndex;
174 bool isVolatile;
175 bool isReferrersClass;
176 uint32_t fieldIdx = mir->dalvikInsn.vB;
177 bool fastPath =
178 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
179 fieldOffset, ssbIndex,
180 isReferrersClass, isVolatile);
181 if (fastPath && !SLOW_FIELD_PATH) {
182 DCHECK_GE(fieldOffset, 0);
183 int rBase;
184 int rMethod;
185 if (isReferrersClass) {
186 // Fast path, static storage base is this method's class
187 rMethod = loadCurrMethod(cUnit);
188 rBase = oatAllocTemp(cUnit);
189 loadWordDisp(cUnit, rMethod,
190 Method::DeclaringClassOffset().Int32Value(), rBase);
191 } else {
192 // Medium path, static storage base in a different class which
193 // requires checks that the other class is initialized.
194 DCHECK_GE(ssbIndex, 0);
195 // May do runtime call so everything to home locations.
196 oatFlushAllRegs(cUnit);
197 // Using fixed register to sync with possible call to runtime
198 // support.
199 rMethod = r1;
200 oatLockTemp(cUnit, rMethod);
201 loadCurrMethodDirect(cUnit, rMethod);
202 rBase = r0;
203 oatLockTemp(cUnit, rBase);
204 loadWordDisp(cUnit, rMethod,
205 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
206 rBase);
207 loadWordDisp(cUnit, rBase,
208 Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
209 rBase);
210 // rBase now points at appropriate static storage base (Class*)
211 // or NULL if not initialized. Check for NULL and call helper if NULL.
212 // TUNING: fast path should fall through
213 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
214 loadWordDisp(cUnit, rSELF,
215 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
216 loadConstant(cUnit, r0, ssbIndex);
217 callRuntimeHelper(cUnit, rLR);
218 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
219 skipTarget->defMask = ENCODE_ALL;
220 branchOver->generic.target = (LIR*)skipTarget;
221 }
222 // rBase now holds static storage base
223 oatFreeTemp(cUnit, rMethod);
224 if (isLongOrDouble) {
225 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
226 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
227 } else {
228 rlSrc = oatGetSrc(cUnit, mir, 0);
229 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
230 }
231 if (isVolatile) {
buzbee12246b82011-09-29 14:15:05 -0700232 oatGenMemBarrier(cUnit, kST);
233 }
Ian Rogers1bddec32012-02-04 12:27:34 -0800234 if (isLongOrDouble) {
235 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
236 rlSrc.highReg);
237 } else {
238 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
239 }
240 if (isVolatile) {
buzbee1da522d2011-09-04 11:22:20 -0700241 oatGenMemBarrier(cUnit, kSY);
242 }
buzbee1da522d2011-09-04 11:22:20 -0700243 if (isObject) {
244 markGCCard(cUnit, rlSrc.lowReg, rBase);
245 }
246 oatFreeTemp(cUnit, rBase);
Ian Rogers1bddec32012-02-04 12:27:34 -0800247 } else {
248 oatFlushAllRegs(cUnit); // Everything to home locations
249 int setterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pSet64Static) :
250 (isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
251 : OFFSETOF_MEMBER(Thread, pSet32Static));
252 loadWordDisp(cUnit, rSELF, setterOffset, rLR);
253 loadConstant(cUnit, r0, fieldIdx);
254 if (isLongOrDouble) {
255 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
256 } else {
257 loadValueDirect(cUnit, rlSrc, r1);
258 }
259 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700260 }
buzbee67bf8852011-08-17 17:51:35 -0700261}
262
Ian Rogers1bddec32012-02-04 12:27:34 -0800263STATIC void genSget(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
264 bool isLongOrDouble, bool isObject)
buzbee67bf8852011-08-17 17:51:35 -0700265{
Ian Rogers1bddec32012-02-04 12:27:34 -0800266 int fieldOffset;
267 int ssbIndex;
268 bool isVolatile;
269 bool isReferrersClass;
270 uint32_t fieldIdx = mir->dalvikInsn.vB;
271 bool fastPath =
272 cUnit->compiler->ComputeStaticFieldInfo(fieldIdx, cUnit,
273 fieldOffset, ssbIndex,
274 isReferrersClass, isVolatile);
275 if (fastPath && !SLOW_FIELD_PATH) {
276 DCHECK_GE(fieldOffset, 0);
277 int rBase;
278 int rMethod;
279 if (isReferrersClass) {
280 // Fast path, static storage base is this method's class
281 rMethod = loadCurrMethod(cUnit);
282 rBase = oatAllocTemp(cUnit);
283 loadWordDisp(cUnit, rMethod,
284 Method::DeclaringClassOffset().Int32Value(), rBase);
285 } else {
286 // Medium path, static storage base in a different class which
287 // requires checks that the other class is initialized
288 DCHECK_GE(ssbIndex, 0);
289 // May do runtime call so everything to home locations.
290 oatFlushAllRegs(cUnit);
291 // Using fixed register to sync with possible call to runtime
292 // support
293 rMethod = r1;
294 oatLockTemp(cUnit, rMethod);
295 loadCurrMethodDirect(cUnit, rMethod);
296 rBase = r0;
297 oatLockTemp(cUnit, rBase);
298 loadWordDisp(cUnit, rMethod,
299 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
300 rBase);
301 loadWordDisp(cUnit, rBase,
302 Array::DataOffset().Int32Value() + sizeof(int32_t*) * ssbIndex,
303 rBase);
304 // rBase now points at appropriate static storage base (Class*)
305 // or NULL if not initialized. Check for NULL and call helper if NULL.
306 // TUNING: fast path should fall through
307 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
308 loadWordDisp(cUnit, rSELF,
309 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
310 loadConstant(cUnit, r0, ssbIndex);
311 callRuntimeHelper(cUnit, rLR);
312 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
313 skipTarget->defMask = ENCODE_ALL;
314 branchOver->generic.target = (LIR*)skipTarget;
315 }
316 // rBase now holds static storage base
317 oatFreeTemp(cUnit, rMethod);
318 rlDest = isLongOrDouble ? oatGetDestWide(cUnit, mir, 0, 1)
319 : oatGetDest(cUnit, mir, 0);
buzbee1da522d2011-09-04 11:22:20 -0700320 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
Ian Rogers1bddec32012-02-04 12:27:34 -0800321 if (isVolatile) {
buzbee1da522d2011-09-04 11:22:20 -0700322 oatGenMemBarrier(cUnit, kSY);
323 }
Ian Rogers1bddec32012-02-04 12:27:34 -0800324 if (isLongOrDouble) {
325 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
326 rlResult.highReg, INVALID_SREG);
327 } else {
328 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
329 }
buzbee1da522d2011-09-04 11:22:20 -0700330 oatFreeTemp(cUnit, rBase);
Ian Rogers1bddec32012-02-04 12:27:34 -0800331 if (isLongOrDouble) {
332 storeValueWide(cUnit, rlDest, rlResult);
333 } else {
334 storeValue(cUnit, rlDest, rlResult);
335 }
336 } else {
337 oatFlushAllRegs(cUnit); // Everything to home locations
338 int getterOffset = isLongOrDouble ? OFFSETOF_MEMBER(Thread, pGet64Static) :
339 (isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
340 : OFFSETOF_MEMBER(Thread, pGet32Static));
341 loadWordDisp(cUnit, rSELF, getterOffset, rLR);
342 loadConstant(cUnit, r0, fieldIdx);
343 callRuntimeHelper(cUnit, rLR);
344 if (isLongOrDouble) {
345 RegLocation rlResult = oatGetReturnWide(cUnit);
346 storeValueWide(cUnit, rlDest, rlResult);
347 } else {
348 RegLocation rlResult = oatGetReturn(cUnit);
349 storeValue(cUnit, rlDest, rlResult);
350 }
buzbeee1931742011-08-28 21:15:53 -0700351 }
buzbee67bf8852011-08-17 17:51:35 -0700352}
353
buzbee561227c2011-09-02 15:28:19 -0700354typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
355 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700356
357/*
358 * Bit of a hack here - in leiu of a real scheduling pass,
359 * emit the next instruction in static & direct invoke sequences.
360 */
buzbeeed3e9302011-09-23 17:34:19 -0700361STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700362 DecodedInstruction* dInsn, int state,
363 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700364{
buzbee561227c2011-09-02 15:28:19 -0700365 DCHECK(rollback == NULL);
366 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700367 switch(state) {
368 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700369 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700370 break;
buzbee561227c2011-09-02 15:28:19 -0700371 case 1: // Get method->code_and_direct_methods_
372 loadWordDisp(cUnit, r0,
373 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
374 r0);
buzbee67bf8852011-08-17 17:51:35 -0700375 break;
buzbee561227c2011-09-02 15:28:19 -0700376 case 2: // Grab target method* and target code_
377 loadWordDisp(cUnit, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800378 CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
buzbee561227c2011-09-02 15:28:19 -0700379 loadWordDisp(cUnit, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800380 CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700381 break;
382 default:
383 return -1;
384 }
385 return state + 1;
386}
387
buzbee67bf8852011-08-17 17:51:35 -0700388/*
389 * Bit of a hack here - in leiu of a real scheduling pass,
390 * emit the next instruction in a virtual invoke sequence.
391 * We can use rLR as a temp prior to target address loading
392 * Note also that we'll load the first argument ("this") into
393 * r1 here rather than the standard loadArgRegs.
394 */
buzbeeed3e9302011-09-23 17:34:19 -0700395STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700396 DecodedInstruction* dInsn, int state,
397 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700398{
buzbee561227c2011-09-02 15:28:19 -0700399 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700400 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700401 /*
402 * This is the fast path in which the target virtual method is
403 * fully resolved at compile time.
404 */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800405 Method* baseMethod = cUnit->class_linker->ResolveMethod(*cUnit->dex_file,
406 dInsn->vB,
407 cUnit->dex_cache,
408 cUnit->class_loader,
409 false);
buzbee561227c2011-09-02 15:28:19 -0700410 CHECK(baseMethod != NULL);
411 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700412 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700413 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700414 rlArg = oatGetSrc(cUnit, mir, 0);
415 loadValueDirectFixed(cUnit, rlArg, r1);
416 break;
buzbee561227c2011-09-02 15:28:19 -0700417 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700418 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700419 // get this->klass_ [use r1, set rLR]
420 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700421 break;
buzbee561227c2011-09-02 15:28:19 -0700422 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
423 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700424 break;
buzbee561227c2011-09-02 15:28:19 -0700425 case 3: // Get target method [use rLR, set r0]
426 loadWordDisp(cUnit, rLR, (target_idx * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800427 Array::DataOffset().Int32Value(), r0);
buzbee561227c2011-09-02 15:28:19 -0700428 break;
429 case 4: // Get the target compiled code address [uses r0, sets rLR]
430 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700431 break;
432 default:
433 return -1;
434 }
435 return state + 1;
436}
437
buzbeeed3e9302011-09-23 17:34:19 -0700438STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700439 DecodedInstruction* dInsn, int state,
440 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700441{
442 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700443 ArmLIR* skipBranch;
444 ArmLIR* skipTarget;
445 /*
446 * This handles the case in which the base method is not fully
447 * resolved at compile time. We must generate code to test
448 * for resolution a run time, bail to the slow path if not to
449 * fill in all the tables. In the latter case, we'll restart at
450 * at the beginning of the sequence.
451 */
buzbee7b1b86d2011-08-26 18:59:10 -0700452 switch(state) {
453 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700454 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700455 break;
buzbee561227c2011-09-02 15:28:19 -0700456 case 1: // Get method->dex_cache_resolved_methods_
457 loadWordDisp(cUnit, r0,
458 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700459 break;
buzbee561227c2011-09-02 15:28:19 -0700460 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
461 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800462 Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700463 break;
buzbee561227c2011-09-02 15:28:19 -0700464 case 3: // Resolved?
465 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
466 // Slowest path, bail to helper, rollback and retry
467 loadWordDisp(cUnit, rSELF,
468 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
469 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -0800470 loadConstant(cUnit, r2, false);
Ian Rogersff1ed472011-09-20 13:46:24 -0700471 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700472 genUnconditionalBranch(cUnit, rollback);
473 // Resume normal slow path
474 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
475 skipTarget->defMask = ENCODE_ALL;
476 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700477 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700478 loadBaseDisp(cUnit, mir, rLR,
479 Method::GetMethodIndexOffset().Int32Value(), r0,
480 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700481 // Load "this" [set r1]
482 rlArg = oatGetSrc(cUnit, mir, 0);
483 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700484 break;
485 case 4:
486 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700487 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700488 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700489 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700490 break;
buzbee561227c2011-09-02 15:28:19 -0700491 case 5:
492 // get this->klass_->vtable_ [usr rLR, set rLR]
493 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800494 DCHECK_EQ((Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700495 // In load shadow fold vtable_ object header size into method_index_
496 opRegImm(cUnit, kOpAdd, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800497 Array::DataOffset().Int32Value() / 4);
buzbee561227c2011-09-02 15:28:19 -0700498 // Get target Method*
499 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
500 break;
501 case 6: // Get the target compiled code address [uses r0, sets rLR]
502 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700503 break;
504 default:
505 return -1;
506 }
507 return state + 1;
508}
509
buzbeeed3e9302011-09-23 17:34:19 -0700510STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700511 DecodedInstruction* dInsn, int callState,
512 NextCallInsn nextCallInsn, ArmLIR* rollback,
513 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700514{
buzbeec0ecd652011-09-25 18:11:54 -0700515 int nextReg = r1;
516 int nextArg = 0;
517 if (skipThis) {
518 nextReg++;
519 nextArg++;
520 }
521 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
522 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
523 rlArg = oatUpdateRawLoc(cUnit, rlArg);
524 if (rlArg.wide && (nextReg <= r2)) {
525 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
526 nextReg++;
527 nextArg++;
528 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700529 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700530 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700531 }
buzbeec0ecd652011-09-25 18:11:54 -0700532 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700533 }
534 return callState;
535}
536
buzbee4a3164f2011-09-03 11:25:10 -0700537// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700538STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700539 DecodedInstruction* dInsn, int state,
540 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700541{
buzbee510c6052011-10-27 10:47:20 -0700542 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700543 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700544 case 0: // Load trampoline target
545 loadWordDisp(cUnit, rSELF,
546 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
547 rLR);
548 // Load r0 with method index
549 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700550 break;
buzbee67bf8852011-08-17 17:51:35 -0700551 default:
552 return -1;
553 }
554 return state + 1;
555}
556
buzbee67bf8852011-08-17 17:51:35 -0700557/*
558 * Interleave launch code for INVOKE_SUPER. See comments
559 * for nextVCallIns.
560 */
buzbeeed3e9302011-09-23 17:34:19 -0700561STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700562 DecodedInstruction* dInsn, int state,
563 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700564{
buzbee4a3164f2011-09-03 11:25:10 -0700565 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700566 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700567 /*
568 * This is the fast path in which the target virtual method is
569 * fully resolved at compile time. Note also that this path assumes
570 * that the check to verify that the target method index falls
571 * within the size of the super's vtable has been done at compile-time.
572 */
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800573 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -0800574 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
575 dInsn->vB,
576 cUnit->dex_cache,
577 cUnit->class_loader,
578 false);
buzbee4a3164f2011-09-03 11:25:10 -0700579 CHECK(baseMethod != NULL);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800580 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
581 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
582 Class* superClass = (declaring_class != NULL)
583 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -0700584 CHECK(superClass != NULL);
585 int32_t target_idx = baseMethod->GetMethodIndex();
586 CHECK(superClass->GetVTable()->GetLength() > target_idx);
587 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
588 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700589 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700590 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700591 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700592 // Load "this" [set r1]
593 rlArg = oatGetSrc(cUnit, mir, 0);
594 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700595 // Get method->declaring_class_ [use r0, set rLR]
596 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
597 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700598 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700599 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700600 break;
601 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
602 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
603 rLR);
604 break;
605 case 2: // Get ...->super_class_->vtable [u/s rLR]
606 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
607 break;
608 case 3: // Get target method [use rLR, set r0]
609 loadWordDisp(cUnit, rLR, (target_idx * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800610 Array::DataOffset().Int32Value(), r0);
buzbee4a3164f2011-09-03 11:25:10 -0700611 break;
612 case 4: // Get the target compiled code address [uses r0, sets rLR]
613 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
614 break;
buzbee67bf8852011-08-17 17:51:35 -0700615 default:
616 return -1;
617 }
buzbee4a3164f2011-09-03 11:25:10 -0700618 return state + 1;
619}
620
621/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700622STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700623 DecodedInstruction* dInsn, int state,
624 ArmLIR* rollback)
625{
buzbee4a3164f2011-09-03 11:25:10 -0700626 RegLocation rlArg;
627 ArmLIR* skipBranch;
628 ArmLIR* skipTarget;
629 int tReg;
630 /*
631 * This handles the case in which the base method is not fully
632 * resolved at compile time. We must generate code to test
633 * for resolution a run time, bail to the slow path if not to
634 * fill in all the tables. In the latter case, we'll restart at
635 * at the beginning of the sequence.
636 */
637 switch(state) {
638 case 0: // Get the current Method* [sets r0]
639 loadCurrMethodDirect(cUnit, r0);
640 break;
buzbee34c77ad2012-01-11 13:01:32 -0800641 case 1: // Get method->dex_cache_resolved_methods_ [uses r0, set rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700642 loadWordDisp(cUnit, r0,
643 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
644 break;
645 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
646 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800647 Array::DataOffset().Int32Value(), rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700648 break;
649 case 3: // Resolved?
650 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
651 // Slowest path, bail to helper, rollback and retry
652 loadWordDisp(cUnit, rSELF,
653 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
654 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -0800655 loadConstant(cUnit, r2, true);
Ian Rogersff1ed472011-09-20 13:46:24 -0700656 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700657 genUnconditionalBranch(cUnit, rollback);
658 // Resume normal slow path
659 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
660 skipTarget->defMask = ENCODE_ALL;
661 skipBranch->generic.target = (LIR*)skipTarget;
662 // Get base_method->method_index [usr rLR, set rLR]
663 loadBaseDisp(cUnit, mir, rLR,
664 Method::GetMethodIndexOffset().Int32Value(), rLR,
665 kUnsignedHalf, INVALID_SREG);
666 // Load "this" [set r1]
667 rlArg = oatGetSrc(cUnit, mir, 0);
668 loadValueDirectFixed(cUnit, rlArg, r1);
669 // Load curMethod->declaring_class_ [uses r0, sets r0]
670 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
671 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700672 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700673 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700674 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700675 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
676 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700677 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700678 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700679 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700680 // Range check, throw NSM on failure
681 tReg = oatAllocTemp(cUnit);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800682 loadWordDisp(cUnit, r0, Array::LengthOffset().Int32Value(),
buzbee4a3164f2011-09-03 11:25:10 -0700683 tReg);
buzbee13ac45a2012-01-12 12:30:16 -0800684 genRegRegCheck(cUnit, kArmCondCs, rLR, tReg, mir,
buzbeeec5adf32011-09-11 15:25:43 -0700685 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700686 oatFreeTemp(cUnit, tReg);
687 }
buzbee6a0f7f52011-09-05 16:14:20 -0700688 // Adjust vtable_ base past object header
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800689 opRegImm(cUnit, kOpAdd, r0, Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700690 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700691 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700692 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700693 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700694 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
695 break;
696 default:
697 return -1;
698 }
buzbee67bf8852011-08-17 17:51:35 -0700699 return state + 1;
700}
701
702/*
703 * Load up to 5 arguments, the first three of which will be in
704 * r1 .. r3. On entry r0 contains the current method pointer,
705 * and as part of the load sequence, it must be replaced with
706 * the target method pointer. Note, this may also be called
707 * for "range" variants if the number of arguments is 5 or fewer.
708 */
buzbeeed3e9302011-09-23 17:34:19 -0700709STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700710 DecodedInstruction* dInsn, int callState,
711 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700712 NextCallInsn nextCallInsn, ArmLIR* rollback,
713 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700714{
715 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700716
717 /* If no arguments, just return */
718 if (dInsn->vA == 0)
719 return callState;
720
buzbee561227c2011-09-02 15:28:19 -0700721 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700722
buzbeec0ecd652011-09-25 18:11:54 -0700723 DCHECK_LE(dInsn->vA, 5U);
724 if (dInsn->vA > 3) {
725 uint32_t nextUse = 3;
726 //Detect special case of wide arg spanning arg3/arg4
727 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
728 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
729 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
730 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
731 rlUse2.wide) {
732 int reg;
733 // Wide spans, we need the 2nd half of uses[2].
734 rlArg = oatUpdateLocWide(cUnit, rlUse2);
735 if (rlArg.location == kLocPhysReg) {
736 reg = rlArg.highReg;
737 } else {
738 // r2 & r3 can safely be used here
739 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700740 loadWordDisp(cUnit, rSP,
741 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
buzbeec0ecd652011-09-25 18:11:54 -0700742 callState = nextCallInsn(cUnit, mir, dInsn, callState,
743 rollback);
744 }
745 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
746 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
747 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
748 nextUse++;
749 }
750 // Loop through the rest
751 while (nextUse < dInsn->vA) {
752 int lowReg;
753 int highReg;
754 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
755 rlArg = oatUpdateRawLoc(cUnit, rlArg);
756 if (rlArg.location == kLocPhysReg) {
757 lowReg = rlArg.lowReg;
758 highReg = rlArg.highReg;
759 } else {
760 lowReg = r2;
761 highReg = r3;
762 if (rlArg.wide) {
763 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
764 } else {
765 loadValueDirectFixed(cUnit, rlArg, lowReg);
766 }
767 callState = nextCallInsn(cUnit, mir, dInsn, callState,
768 rollback);
769 }
770 int outsOffset = (nextUse + 1) * 4;
771 if (rlArg.wide) {
772 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
773 nextUse += 2;
774 } else {
775 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
776 nextUse++;
777 }
buzbee561227c2011-09-02 15:28:19 -0700778 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700779 }
buzbee67bf8852011-08-17 17:51:35 -0700780 }
781
buzbeec0ecd652011-09-25 18:11:54 -0700782 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
783 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700784
buzbee67bf8852011-08-17 17:51:35 -0700785 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700786 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700787 }
788 return callState;
789}
790
791/*
792 * May have 0+ arguments (also used for jumbo). Note that
793 * source virtual registers may be in physical registers, so may
794 * need to be flushed to home location before copying. This
795 * applies to arg3 and above (see below).
796 *
797 * Two general strategies:
798 * If < 20 arguments
799 * Pass args 3-18 using vldm/vstm block copy
800 * Pass arg0, arg1 & arg2 in r1-r3
801 * If 20+ arguments
802 * Pass args arg19+ using memcpy block copy
803 * Pass arg0, arg1 & arg2 in r1-r3
804 *
805 */
buzbeeed3e9302011-09-23 17:34:19 -0700806STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700807 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700808 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700809 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700810{
811 int firstArg = dInsn->vC;
812 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700813
buzbee67bf8852011-08-17 17:51:35 -0700814 // If we can treat it as non-range (Jumbo ops will use range form)
815 if (numArgs <= 5)
816 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700817 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700818 /*
819 * Make sure range list doesn't span the break between in normal
820 * Dalvik vRegs and the ins.
821 */
buzbee1b4c8592011-08-31 10:43:51 -0700822 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800823 int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee1b4c8592011-08-31 10:43:51 -0700824 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
825 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700826 }
827
828 /*
829 * First load the non-register arguments. Both forms expect all
830 * of the source arguments to be in their home frame location, so
831 * scan the sReg names and flush any that have been promoted to
832 * frame backing storage.
833 */
834 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700835 for (int nextArg = 0; nextArg < numArgs;) {
836 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700837 if (loc.wide) {
838 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700839 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700840 storeBaseDispWide(cUnit, rSP,
841 oatSRegOffset(cUnit, loc.sRegLow),
842 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700843 }
buzbeec0ecd652011-09-25 18:11:54 -0700844 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700845 } else {
846 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700847 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700848 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
849 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700850 }
buzbeec0ecd652011-09-25 18:11:54 -0700851 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700852 }
853 }
854
buzbee67bc2362011-10-11 18:08:40 -0700855 int startOffset = oatSRegOffset(cUnit,
856 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700857 int outsOffset = 4 /* Method* */ + (3 * 4);
858 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700859 // Generate memcpy
860 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
861 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700862 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
863 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700864 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700865 // Restore Method*
866 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700867 } else {
868 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700869 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700870 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700871 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700872 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
873 //TUNING: loosen barrier
874 ld->defMask = ENCODE_ALL;
875 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700876 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700877 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700878 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700879 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
880 setMemRefType(st, false /* isLoad */, kDalvikReg);
881 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700882 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700883 }
884
buzbeec0ecd652011-09-25 18:11:54 -0700885 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
886 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700887
buzbee561227c2011-09-02 15:28:19 -0700888 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee99f27232011-10-05 12:56:36 -0700889 if (pcrLabel) {
890 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
891 }
buzbee67bf8852011-08-17 17:51:35 -0700892 return callState;
893}
894
buzbee2a475e72011-09-07 17:19:17 -0700895// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700896STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700897{
898 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
899 loadWordDisp(cUnit, rSELF,
900 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
901 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
902 target->defMask = -1;
903 branchOver->generic.target = (LIR*)target;
904}
buzbee2a475e72011-09-07 17:19:17 -0700905
buzbeeed3e9302011-09-23 17:34:19 -0700906STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700907 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700908{
909 DecodedInstruction* dInsn = &mir->dalvikInsn;
910 int callState = 0;
911 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700912 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700913 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700914 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700915
buzbee109bd6a2011-09-06 13:58:41 -0700916 // Explicit register usage
917 oatLockCallTemps(cUnit);
918
buzbee99f27232011-10-05 12:56:36 -0700919 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
920 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
921 int idx = mir->dalvikInsn.vB;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800922 Method* target = cUnit->dex_cache->GetResolvedMethods()->Get(idx);
buzbee99f27232011-10-05 12:56:36 -0700923 if (target) {
924 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
925 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
926 loadValueDirectFixed(cUnit, rlArg, r0);
927 loadWordDisp(cUnit, rSELF,
928 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
929 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
930 opReg(cUnit, kOpBlx, rLR);
931 oatClobberCalleeSave(cUnit);
932 return;
933 }
934 }
935 }
936
buzbee561227c2011-09-02 15:28:19 -0700937 if (range) {
938 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700939 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700940 } else {
941 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700942 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700943 }
buzbee67bf8852011-08-17 17:51:35 -0700944 // Finish up any of the call sequence not interleaved in arg loading
945 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700946 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700947 }
buzbeece302932011-10-04 14:32:18 -0700948 if (DISPLAY_MISSING_TARGETS) {
949 genShowTarget(cUnit);
950 }
buzbeeec5adf32011-09-11 15:25:43 -0700951 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700952 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700953}
954
buzbee4a3164f2011-09-03 11:25:10 -0700955/*
956 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
957 * which will locate the target and continue on via a tail call.
958 */
buzbeeed3e9302011-09-23 17:34:19 -0700959STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -0700960{
961 DecodedInstruction* dInsn = &mir->dalvikInsn;
962 int callState = 0;
963 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -0700964 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -0700965
966 // Explicit register usage
967 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700968 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700969 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700970 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
971 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700972 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -0700973 false);
buzbee67bf8852011-08-17 17:51:35 -0700974 else
975 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -0700976 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -0700977 // Finish up any of the call sequence not interleaved in arg loading
978 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700979 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700980 }
buzbeece302932011-10-04 14:32:18 -0700981 if (DISPLAY_MISSING_TARGETS) {
982 genShowTarget(cUnit);
983 }
buzbeeec5adf32011-09-11 15:25:43 -0700984 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700985 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700986}
987
buzbeeed3e9302011-09-23 17:34:19 -0700988STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -0700989{
990 DecodedInstruction* dInsn = &mir->dalvikInsn;
991 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -0700992 ArmLIR* rollback;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800993 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -0800994 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
995 dInsn->vB,
996 cUnit->dex_cache,
997 cUnit->class_loader,
998 false);
buzbee4a3164f2011-09-03 11:25:10 -0700999 NextCallInsn nextCallInsn;
1000 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001001 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001002
1003 // Explicit register usage
1004 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -08001005
1006 // For testing, force call to artResolveMethodFromCode & ignore result
1007 if (EXERCISE_RESOLVE_METHOD) {
1008 loadCurrMethodDirect(cUnit, r0);
1009 loadWordDisp(cUnit, rSELF,
1010 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
1011 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -08001012 loadConstant(cUnit, r2, true);
buzbee34c77ad2012-01-11 13:01:32 -08001013 callRuntimeHelper(cUnit, rLR);
1014 }
1015
buzbee34cd9e52011-09-08 14:31:52 -07001016 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001017 Thread* thread = Thread::Current();
1018 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1019 thread->ClearException();
1020 }
buzbee4a3164f2011-09-03 11:25:10 -07001021 fastPath = false;
1022 } else {
Ian Rogersa3760aa2011-11-14 14:32:37 -08001023 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
1024 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
1025 Class* superClass = (declaring_class != NULL)
1026 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -07001027 if (superClass == NULL) {
1028 fastPath = false;
1029 } else {
1030 int32_t target_idx = baseMethod->GetMethodIndex();
1031 if (superClass->GetVTable()->GetLength() <= target_idx) {
1032 fastPath = false;
1033 } else {
1034 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1035 }
1036 }
1037 }
1038 if (fastPath) {
1039 nextCallInsn = nextSuperCallInsn;
1040 rollback = NULL;
1041 } else {
1042 nextCallInsn = nextSuperCallInsnSP;
1043 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1044 rollback->defMask = -1;
1045 }
buzbee67bf8852011-08-17 17:51:35 -07001046 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001047 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001048 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001049 else
buzbeec0ecd652011-09-25 18:11:54 -07001050 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001051 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001052 // Finish up any of the call sequence not interleaved in arg loading
1053 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001054 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001055 }
buzbeece302932011-10-04 14:32:18 -07001056 if (DISPLAY_MISSING_TARGETS) {
1057 genShowTarget(cUnit);
1058 }
buzbeeec5adf32011-09-11 15:25:43 -07001059 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001060 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001061}
1062
buzbeeed3e9302011-09-23 17:34:19 -07001063STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001064{
1065 DecodedInstruction* dInsn = &mir->dalvikInsn;
1066 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001067 ArmLIR* rollback;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001068 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001069 Method* method = class_linker->ResolveMethod(*cUnit->dex_file,
1070 dInsn->vB,
1071 cUnit->dex_cache,
1072 cUnit->class_loader,
1073 false);
buzbee561227c2011-09-02 15:28:19 -07001074 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001075 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001076 // Explicit register usage
1077 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -08001078
1079 // For testing, force call to artResolveMethodFromCode & ignore result
1080 if (EXERCISE_RESOLVE_METHOD) {
1081 loadCurrMethodDirect(cUnit, r0);
1082 loadWordDisp(cUnit, rSELF,
1083 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
1084 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -08001085 loadConstant(cUnit, r2, false);
buzbee34c77ad2012-01-11 13:01:32 -08001086 callRuntimeHelper(cUnit, rLR);
1087 }
1088
buzbee34cd9e52011-09-08 14:31:52 -07001089 if (SLOW_INVOKE_PATH || method == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001090 Thread* thread = Thread::Current();
1091 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1092 thread->ClearException();
1093 }
buzbee561227c2011-09-02 15:28:19 -07001094 // Slow path
1095 nextCallInsn = nextVCallInsnSP;
1096 // If we need a slow-path callout, we'll restart here
1097 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1098 rollback->defMask = -1;
1099 } else {
1100 // Fast path
1101 nextCallInsn = nextVCallInsn;
1102 rollback = NULL;
1103 }
buzbee67bf8852011-08-17 17:51:35 -07001104 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001105 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001106 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001107 else
buzbeec0ecd652011-09-25 18:11:54 -07001108 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001109 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001110 // Finish up any of the call sequence not interleaved in arg loading
1111 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001112 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001113 }
buzbeece302932011-10-04 14:32:18 -07001114 if (DISPLAY_MISSING_TARGETS) {
1115 genShowTarget(cUnit);
1116 }
buzbeeec5adf32011-09-11 15:25:43 -07001117 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001118 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001119}
1120
buzbeeed3e9302011-09-23 17:34:19 -07001121STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001122 BasicBlock* bb, ArmLIR* labelList)
1123{
1124 bool res = false; // Assume success
1125 RegLocation rlSrc[3];
1126 RegLocation rlDest = badLoc;
1127 RegLocation rlResult = badLoc;
1128 Opcode opcode = mir->dalvikInsn.opcode;
1129
1130 /* Prep Src and Dest locations */
1131 int nextSreg = 0;
1132 int nextLoc = 0;
1133 int attrs = oatDataFlowAttributes[opcode];
1134 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1135 if (attrs & DF_UA) {
1136 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1137 nextSreg++;
1138 } else if (attrs & DF_UA_WIDE) {
1139 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1140 nextSreg + 1);
1141 nextSreg+= 2;
1142 }
1143 if (attrs & DF_UB) {
1144 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1145 nextSreg++;
1146 } else if (attrs & DF_UB_WIDE) {
1147 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1148 nextSreg + 1);
1149 nextSreg+= 2;
1150 }
1151 if (attrs & DF_UC) {
1152 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1153 } else if (attrs & DF_UC_WIDE) {
1154 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1155 nextSreg + 1);
1156 }
1157 if (attrs & DF_DA) {
1158 rlDest = oatGetDest(cUnit, mir, 0);
1159 } else if (attrs & DF_DA_WIDE) {
1160 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1161 }
1162
1163 switch(opcode) {
1164 case OP_NOP:
1165 break;
1166
1167 case OP_MOVE_EXCEPTION:
1168 int exOffset;
1169 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001170 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001171 resetReg = oatAllocTemp(cUnit);
1172 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1173 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1174 loadConstant(cUnit, resetReg, 0);
1175 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1176 storeValue(cUnit, rlDest, rlResult);
1177 break;
1178
1179 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -07001180 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001181 break;
1182
1183 case OP_RETURN:
1184 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -07001185 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001186 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001187 break;
1188
1189 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -07001190 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001191 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001192 break;
1193
1194 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001195 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001196 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001197 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001198 break;
1199
1200 case OP_MOVE_RESULT:
1201 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001202 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001203 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001204 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001205 break;
1206
1207 case OP_MOVE:
1208 case OP_MOVE_OBJECT:
1209 case OP_MOVE_16:
1210 case OP_MOVE_OBJECT_16:
1211 case OP_MOVE_FROM16:
1212 case OP_MOVE_OBJECT_FROM16:
1213 storeValue(cUnit, rlDest, rlSrc[0]);
1214 break;
1215
1216 case OP_MOVE_WIDE:
1217 case OP_MOVE_WIDE_16:
1218 case OP_MOVE_WIDE_FROM16:
1219 storeValueWide(cUnit, rlDest, rlSrc[0]);
1220 break;
1221
1222 case OP_CONST:
1223 case OP_CONST_4:
1224 case OP_CONST_16:
1225 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1226 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1227 storeValue(cUnit, rlDest, rlResult);
1228 break;
1229
1230 case OP_CONST_HIGH16:
1231 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1232 loadConstantNoClobber(cUnit, rlResult.lowReg,
1233 mir->dalvikInsn.vB << 16);
1234 storeValue(cUnit, rlDest, rlResult);
1235 break;
1236
1237 case OP_CONST_WIDE_16:
1238 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001239 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1240 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1241 mir->dalvikInsn.vB,
1242 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001243 storeValueWide(cUnit, rlDest, rlResult);
1244 break;
1245
1246 case OP_CONST_WIDE:
1247 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1248 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001249 mir->dalvikInsn.vB_wide & 0xffffffff,
1250 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001251 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001252 break;
1253
1254 case OP_CONST_WIDE_HIGH16:
1255 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1256 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1257 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001258 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001259 break;
1260
1261 case OP_MONITOR_ENTER:
1262 genMonitorEnter(cUnit, mir, rlSrc[0]);
1263 break;
1264
1265 case OP_MONITOR_EXIT:
1266 genMonitorExit(cUnit, mir, rlSrc[0]);
1267 break;
1268
1269 case OP_CHECK_CAST:
1270 genCheckCast(cUnit, mir, rlSrc[0]);
1271 break;
1272
1273 case OP_INSTANCE_OF:
1274 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1275 break;
1276
1277 case OP_NEW_INSTANCE:
1278 genNewInstance(cUnit, mir, rlDest);
1279 break;
1280
1281 case OP_THROW:
1282 genThrow(cUnit, mir, rlSrc[0]);
1283 break;
1284
buzbee5ade1d22011-09-09 14:44:52 -07001285 case OP_THROW_VERIFICATION_ERROR:
1286 loadWordDisp(cUnit, rSELF,
1287 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1288 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1289 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001290 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001291 break;
1292
buzbee67bf8852011-08-17 17:51:35 -07001293 case OP_ARRAY_LENGTH:
1294 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001295 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001296 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001297 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001298 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1299 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1300 rlResult.lowReg);
1301 storeValue(cUnit, rlDest, rlResult);
1302 break;
1303
1304 case OP_CONST_STRING:
1305 case OP_CONST_STRING_JUMBO:
1306 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1307 break;
1308
1309 case OP_CONST_CLASS:
1310 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1311 break;
1312
1313 case OP_FILL_ARRAY_DATA:
1314 genFillArrayData(cUnit, mir, rlSrc[0]);
1315 break;
1316
1317 case OP_FILLED_NEW_ARRAY:
1318 genFilledNewArray(cUnit, mir, false /* not range */);
1319 break;
1320
1321 case OP_FILLED_NEW_ARRAY_RANGE:
1322 genFilledNewArray(cUnit, mir, true /* range */);
1323 break;
1324
1325 case OP_NEW_ARRAY:
1326 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1327 break;
1328
1329 case OP_GOTO:
1330 case OP_GOTO_16:
1331 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001332 if (bb->taken->startOffset <= mir->offset) {
1333 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001334 }
1335 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1336 break;
1337
1338 case OP_PACKED_SWITCH:
1339 genPackedSwitch(cUnit, mir, rlSrc[0]);
1340 break;
1341
1342 case OP_SPARSE_SWITCH:
1343 genSparseSwitch(cUnit, mir, rlSrc[0]);
1344 break;
1345
1346 case OP_CMPL_FLOAT:
1347 case OP_CMPG_FLOAT:
1348 case OP_CMPL_DOUBLE:
1349 case OP_CMPG_DOUBLE:
1350 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1351 break;
1352
1353 case OP_CMP_LONG:
1354 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1355 break;
1356
1357 case OP_IF_EQ:
1358 case OP_IF_NE:
1359 case OP_IF_LT:
1360 case OP_IF_GE:
1361 case OP_IF_GT:
1362 case OP_IF_LE: {
1363 bool backwardBranch;
1364 ArmConditionCode cond;
1365 backwardBranch = (bb->taken->startOffset <= mir->offset);
1366 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001367 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001368 }
1369 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1370 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1371 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1372 switch(opcode) {
1373 case OP_IF_EQ:
1374 cond = kArmCondEq;
1375 break;
1376 case OP_IF_NE:
1377 cond = kArmCondNe;
1378 break;
1379 case OP_IF_LT:
1380 cond = kArmCondLt;
1381 break;
1382 case OP_IF_GE:
1383 cond = kArmCondGe;
1384 break;
1385 case OP_IF_GT:
1386 cond = kArmCondGt;
1387 break;
1388 case OP_IF_LE:
1389 cond = kArmCondLe;
1390 break;
1391 default:
1392 cond = (ArmConditionCode)0;
1393 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1394 }
1395 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1396 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1397 break;
1398 }
1399
1400 case OP_IF_EQZ:
1401 case OP_IF_NEZ:
1402 case OP_IF_LTZ:
1403 case OP_IF_GEZ:
1404 case OP_IF_GTZ:
1405 case OP_IF_LEZ: {
1406 bool backwardBranch;
1407 ArmConditionCode cond;
1408 backwardBranch = (bb->taken->startOffset <= mir->offset);
1409 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001410 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001411 }
1412 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1413 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1414 switch(opcode) {
1415 case OP_IF_EQZ:
1416 cond = kArmCondEq;
1417 break;
1418 case OP_IF_NEZ:
1419 cond = kArmCondNe;
1420 break;
1421 case OP_IF_LTZ:
1422 cond = kArmCondLt;
1423 break;
1424 case OP_IF_GEZ:
1425 cond = kArmCondGe;
1426 break;
1427 case OP_IF_GTZ:
1428 cond = kArmCondGt;
1429 break;
1430 case OP_IF_LEZ:
1431 cond = kArmCondLe;
1432 break;
1433 default:
1434 cond = (ArmConditionCode)0;
1435 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1436 }
1437 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1438 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1439 break;
1440 }
1441
1442 case OP_AGET_WIDE:
1443 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1444 break;
1445 case OP_AGET:
1446 case OP_AGET_OBJECT:
1447 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1448 break;
1449 case OP_AGET_BOOLEAN:
1450 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1451 rlDest, 0);
1452 break;
1453 case OP_AGET_BYTE:
1454 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1455 break;
1456 case OP_AGET_CHAR:
1457 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1458 rlDest, 1);
1459 break;
1460 case OP_AGET_SHORT:
1461 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1462 break;
1463 case OP_APUT_WIDE:
1464 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1465 break;
1466 case OP_APUT:
1467 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1468 break;
1469 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001470 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001471 break;
1472 case OP_APUT_SHORT:
1473 case OP_APUT_CHAR:
1474 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1475 rlSrc[0], 1);
1476 break;
1477 case OP_APUT_BYTE:
1478 case OP_APUT_BOOLEAN:
1479 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1480 rlSrc[0], 0);
1481 break;
1482
Ian Rogers1bddec32012-02-04 12:27:34 -08001483 case OP_IGET_OBJECT:
1484 case OP_IGET_OBJECT_VOLATILE:
1485 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
1486 break;
1487
buzbee67bf8852011-08-17 17:51:35 -07001488 case OP_IGET_WIDE:
1489 case OP_IGET_WIDE_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001490 genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
buzbee67bf8852011-08-17 17:51:35 -07001491 break;
1492
1493 case OP_IGET:
1494 case OP_IGET_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001495 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
1496 break;
1497
1498 case OP_IGET_CHAR:
1499 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
1500 break;
1501
1502 case OP_IGET_SHORT:
1503 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001504 break;
1505
1506 case OP_IGET_BOOLEAN:
1507 case OP_IGET_BYTE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001508 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001509 break;
1510
1511 case OP_IPUT_WIDE:
1512 case OP_IPUT_WIDE_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001513 genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
buzbee67bf8852011-08-17 17:51:35 -07001514 break;
1515
1516 case OP_IPUT_OBJECT:
1517 case OP_IPUT_OBJECT_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001518 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
buzbee67bf8852011-08-17 17:51:35 -07001519 break;
1520
1521 case OP_IPUT:
1522 case OP_IPUT_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001523 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001524 break;
1525
1526 case OP_IPUT_BOOLEAN:
1527 case OP_IPUT_BYTE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001528 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001529 break;
1530
1531 case OP_IPUT_CHAR:
Ian Rogers1bddec32012-02-04 12:27:34 -08001532 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001533 break;
1534
1535 case OP_IPUT_SHORT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001536 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001537 break;
1538
buzbee67bf8852011-08-17 17:51:35 -07001539 case OP_SGET_OBJECT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001540 genSget(cUnit, mir, rlDest, false, true);
1541 break;
1542 case OP_SGET:
buzbee67bf8852011-08-17 17:51:35 -07001543 case OP_SGET_BOOLEAN:
1544 case OP_SGET_BYTE:
1545 case OP_SGET_CHAR:
1546 case OP_SGET_SHORT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001547 genSget(cUnit, mir, rlDest, false, false);
buzbee67bf8852011-08-17 17:51:35 -07001548 break;
1549
1550 case OP_SGET_WIDE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001551 genSget(cUnit, mir, rlDest, true, false);
buzbee67bf8852011-08-17 17:51:35 -07001552 break;
1553
buzbee67bf8852011-08-17 17:51:35 -07001554 case OP_SPUT_OBJECT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001555 genSput(cUnit, mir, rlSrc[0], false, true);
1556 break;
1557
1558 case OP_SPUT:
buzbee67bf8852011-08-17 17:51:35 -07001559 case OP_SPUT_BOOLEAN:
1560 case OP_SPUT_BYTE:
1561 case OP_SPUT_CHAR:
1562 case OP_SPUT_SHORT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001563 genSput(cUnit, mir, rlSrc[0], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001564 break;
1565
1566 case OP_SPUT_WIDE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001567 genSput(cUnit, mir, rlSrc[0], true, false);
buzbee67bf8852011-08-17 17:51:35 -07001568 break;
1569
1570 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001571 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1572 true /*range*/);
1573 break;
buzbee67bf8852011-08-17 17:51:35 -07001574 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001575 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1576 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001577 break;
1578
1579 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001580 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1581 false /*range*/);
1582 break;
buzbee67bf8852011-08-17 17:51:35 -07001583 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001584 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1585 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001586 break;
1587
1588 case OP_INVOKE_VIRTUAL:
1589 case OP_INVOKE_VIRTUAL_RANGE:
1590 genInvokeVirtual(cUnit, mir);
1591 break;
1592
1593 case OP_INVOKE_SUPER:
1594 case OP_INVOKE_SUPER_RANGE:
1595 genInvokeSuper(cUnit, mir);
1596 break;
1597
1598 case OP_INVOKE_INTERFACE:
1599 case OP_INVOKE_INTERFACE_RANGE:
1600 genInvokeInterface(cUnit, mir);
1601 break;
1602
1603 case OP_NEG_INT:
1604 case OP_NOT_INT:
1605 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1606 break;
1607
1608 case OP_NEG_LONG:
1609 case OP_NOT_LONG:
1610 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1611 break;
1612
1613 case OP_NEG_FLOAT:
1614 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1615 break;
1616
1617 case OP_NEG_DOUBLE:
1618 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1619 break;
1620
1621 case OP_INT_TO_LONG:
1622 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1623 if (rlSrc[0].location == kLocPhysReg) {
1624 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1625 } else {
1626 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1627 }
1628 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1629 rlResult.lowReg, 31);
1630 storeValueWide(cUnit, rlDest, rlResult);
1631 break;
1632
1633 case OP_LONG_TO_INT:
1634 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1635 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1636 storeValue(cUnit, rlDest, rlSrc[0]);
1637 break;
1638
1639 case OP_INT_TO_BYTE:
1640 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1641 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1642 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1643 storeValue(cUnit, rlDest, rlResult);
1644 break;
1645
1646 case OP_INT_TO_SHORT:
1647 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1648 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1649 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1650 storeValue(cUnit, rlDest, rlResult);
1651 break;
1652
1653 case OP_INT_TO_CHAR:
1654 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1655 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1656 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1657 storeValue(cUnit, rlDest, rlResult);
1658 break;
1659
1660 case OP_INT_TO_FLOAT:
1661 case OP_INT_TO_DOUBLE:
1662 case OP_LONG_TO_FLOAT:
1663 case OP_LONG_TO_DOUBLE:
1664 case OP_FLOAT_TO_INT:
1665 case OP_FLOAT_TO_LONG:
1666 case OP_FLOAT_TO_DOUBLE:
1667 case OP_DOUBLE_TO_INT:
1668 case OP_DOUBLE_TO_LONG:
1669 case OP_DOUBLE_TO_FLOAT:
1670 genConversion(cUnit, mir);
1671 break;
1672
1673 case OP_ADD_INT:
1674 case OP_SUB_INT:
1675 case OP_MUL_INT:
1676 case OP_DIV_INT:
1677 case OP_REM_INT:
1678 case OP_AND_INT:
1679 case OP_OR_INT:
1680 case OP_XOR_INT:
1681 case OP_SHL_INT:
1682 case OP_SHR_INT:
1683 case OP_USHR_INT:
1684 case OP_ADD_INT_2ADDR:
1685 case OP_SUB_INT_2ADDR:
1686 case OP_MUL_INT_2ADDR:
1687 case OP_DIV_INT_2ADDR:
1688 case OP_REM_INT_2ADDR:
1689 case OP_AND_INT_2ADDR:
1690 case OP_OR_INT_2ADDR:
1691 case OP_XOR_INT_2ADDR:
1692 case OP_SHL_INT_2ADDR:
1693 case OP_SHR_INT_2ADDR:
1694 case OP_USHR_INT_2ADDR:
1695 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1696 break;
1697
1698 case OP_ADD_LONG:
1699 case OP_SUB_LONG:
1700 case OP_MUL_LONG:
1701 case OP_DIV_LONG:
1702 case OP_REM_LONG:
1703 case OP_AND_LONG:
1704 case OP_OR_LONG:
1705 case OP_XOR_LONG:
1706 case OP_ADD_LONG_2ADDR:
1707 case OP_SUB_LONG_2ADDR:
1708 case OP_MUL_LONG_2ADDR:
1709 case OP_DIV_LONG_2ADDR:
1710 case OP_REM_LONG_2ADDR:
1711 case OP_AND_LONG_2ADDR:
1712 case OP_OR_LONG_2ADDR:
1713 case OP_XOR_LONG_2ADDR:
1714 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1715 break;
1716
buzbee67bf8852011-08-17 17:51:35 -07001717 case OP_SHL_LONG:
1718 case OP_SHR_LONG:
1719 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001720 case OP_SHL_LONG_2ADDR:
1721 case OP_SHR_LONG_2ADDR:
1722 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001723 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1724 break;
1725
1726 case OP_ADD_FLOAT:
1727 case OP_SUB_FLOAT:
1728 case OP_MUL_FLOAT:
1729 case OP_DIV_FLOAT:
1730 case OP_REM_FLOAT:
1731 case OP_ADD_FLOAT_2ADDR:
1732 case OP_SUB_FLOAT_2ADDR:
1733 case OP_MUL_FLOAT_2ADDR:
1734 case OP_DIV_FLOAT_2ADDR:
1735 case OP_REM_FLOAT_2ADDR:
1736 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1737 break;
1738
1739 case OP_ADD_DOUBLE:
1740 case OP_SUB_DOUBLE:
1741 case OP_MUL_DOUBLE:
1742 case OP_DIV_DOUBLE:
1743 case OP_REM_DOUBLE:
1744 case OP_ADD_DOUBLE_2ADDR:
1745 case OP_SUB_DOUBLE_2ADDR:
1746 case OP_MUL_DOUBLE_2ADDR:
1747 case OP_DIV_DOUBLE_2ADDR:
1748 case OP_REM_DOUBLE_2ADDR:
1749 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1750 break;
1751
1752 case OP_RSUB_INT:
1753 case OP_ADD_INT_LIT16:
1754 case OP_MUL_INT_LIT16:
1755 case OP_DIV_INT_LIT16:
1756 case OP_REM_INT_LIT16:
1757 case OP_AND_INT_LIT16:
1758 case OP_OR_INT_LIT16:
1759 case OP_XOR_INT_LIT16:
1760 case OP_ADD_INT_LIT8:
1761 case OP_RSUB_INT_LIT8:
1762 case OP_MUL_INT_LIT8:
1763 case OP_DIV_INT_LIT8:
1764 case OP_REM_INT_LIT8:
1765 case OP_AND_INT_LIT8:
1766 case OP_OR_INT_LIT8:
1767 case OP_XOR_INT_LIT8:
1768 case OP_SHL_INT_LIT8:
1769 case OP_SHR_INT_LIT8:
1770 case OP_USHR_INT_LIT8:
1771 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1772 break;
1773
1774 default:
1775 res = true;
1776 }
1777 return res;
1778}
1779
Elliott Hughesc1f143d2011-12-01 17:31:10 -08001780STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001781 "kMirOpPhi",
1782 "kMirOpNullNRangeUpCheck",
1783 "kMirOpNullNRangeDownCheck",
1784 "kMirOpLowerBound",
1785 "kMirOpPunt",
1786 "kMirOpCheckInlinePrediction",
1787};
1788
1789/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001790STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001791{
1792 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
buzbee5abfa3e2012-01-31 17:01:43 -08001793 char* msg = NULL;
1794 if (cUnit->printMe) {
buzbeeba938cb2012-02-03 14:47:55 -08001795 msg = (char*)oatNew(cUnit, strlen(extendedMIROpNames[opOffset]) + 1,
1796 false, kAllocDebugInfo);
buzbee5abfa3e2012-01-31 17:01:43 -08001797 strcpy(msg, extendedMIROpNames[opOffset]);
1798 }
buzbee67bf8852011-08-17 17:51:35 -07001799 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1800
1801 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1802 case kMirOpPhi: {
buzbee5abfa3e2012-01-31 17:01:43 -08001803 char* ssaString = NULL;
1804 if (cUnit->printMe) {
1805 ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1806 }
buzbee67bf8852011-08-17 17:51:35 -07001807 op->flags.isNop = true;
1808 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1809 break;
1810 }
1811 default:
1812 break;
1813 }
1814}
1815
buzbee67bc2362011-10-11 18:08:40 -07001816/*
1817 * If there are any ins passed in registers that have not been promoted
1818 * to a callee-save register, flush them to the frame. Perform intial
1819 * assignment of promoted arguments.
1820 */
buzbeeed3e9302011-09-23 17:34:19 -07001821STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001822{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001823 if (cUnit->numIns == 0)
buzbee67bf8852011-08-17 17:51:35 -07001824 return;
buzbee67bc2362011-10-11 18:08:40 -07001825 int firstArgReg = r1;
1826 int lastArgReg = r3;
Ian Rogersa3760aa2011-11-14 14:32:37 -08001827 int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee8febc582011-10-25 12:39:20 -07001828 /*
1829 * Arguments passed in registers should be flushed
1830 * to their backing locations in the frame for now.
1831 * Also, we need to do initial assignment for promoted
1832 * arguments. NOTE: an older version of dx had an issue
1833 * in which it would reuse static method argument registers.
1834 * This could result in the same Dalvik virtual register
1835 * being promoted to both core and fp regs. In those
1836 * cases, copy argument to both. This will be uncommon
1837 * enough that it isn't worth attempting to optimize.
1838 */
Ian Rogersa3760aa2011-11-14 14:32:37 -08001839 for (int i = 0; i < cUnit->numIns; i++) {
buzbee67bc2362011-10-11 18:08:40 -07001840 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001841 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001842 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001843 if (vMap.coreLocation == kLocPhysReg) {
1844 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001845 }
1846 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001847 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1848 }
1849 // Also put a copy in memory in case we're partially promoted
1850 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1851 firstArgReg + i, kWord);
1852 } else {
buzbee8febc582011-10-25 12:39:20 -07001853 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001854 if (vMap.coreLocation == kLocPhysReg) {
1855 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1856 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001857 }
1858 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001859 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1860 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001861 }
1862 }
buzbee67bf8852011-08-17 17:51:35 -07001863 }
1864}
1865
1866/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001867STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001868{
1869 MIR* mir;
1870 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1871 int blockId = bb->id;
1872
1873 cUnit->curBlock = bb;
1874 labelList[blockId].operands[0] = bb->startOffset;
1875
1876 /* Insert the block label */
1877 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1878 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1879
buzbee6181f792011-09-29 11:14:04 -07001880 /* Reset local optimization data on block boundaries */
1881 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001882 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001883 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001884
1885 ArmLIR* headLIR = NULL;
1886
buzbeebbaf8942011-10-02 13:08:29 -07001887 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001888 if (bb->blockType == kEntryBlock) {
1889 /*
1890 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1891 * mechanism know so it doesn't try to use any of them when
1892 * expanding the frame or flushing. This leaves the utility
1893 * code with a single temp: r12. This should be enough.
1894 */
1895 oatLockTemp(cUnit, r0);
1896 oatLockTemp(cUnit, r1);
1897 oatLockTemp(cUnit, r2);
1898 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001899
1900 /*
1901 * We can safely skip the stack overflow check if we're
1902 * a leaf *and* our frame size < fudge factor.
1903 */
1904 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1905 ((size_t)cUnit->frameSize <
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001906 Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001907 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001908 if (!skipOverflowCheck) {
1909 /* Load stack limit */
1910 loadWordDisp(cUnit, rSELF,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001911 Thread::StackEndOffset().Int32Value(), r12);
buzbeecefd1872011-09-09 09:59:52 -07001912 }
buzbee67bf8852011-08-17 17:51:35 -07001913 /* Spill core callee saves */
1914 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1915 /* Need to spill any FP regs? */
1916 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001917 /*
1918 * NOTE: fp spills are a little different from core spills in that
1919 * they are pushed as a contiguous block. When promoting from
1920 * the fp set, we must allocate all singles from s16..highest-promoted
1921 */
buzbee67bf8852011-08-17 17:51:35 -07001922 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1923 }
buzbeecefd1872011-09-09 09:59:52 -07001924 if (!skipOverflowCheck) {
1925 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001926 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001927 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1928 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001929 genRegCopy(cUnit, rSP, rLR); // Establish stack
1930 } else {
1931 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001932 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001933 }
buzbee67bf8852011-08-17 17:51:35 -07001934 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1935 flushIns(cUnit);
1936 oatFreeTemp(cUnit, r0);
1937 oatFreeTemp(cUnit, r1);
1938 oatFreeTemp(cUnit, r2);
1939 oatFreeTemp(cUnit, r3);
1940 } else if (bb->blockType == kExitBlock) {
1941 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07001942 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07001943 /* Need to restore any FP callee saves? */
1944 if (cUnit->numFPSpills) {
1945 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1946 }
1947 if (cUnit->coreSpillMask & (1 << rLR)) {
1948 /* Unspill rLR to rPC */
1949 cUnit->coreSpillMask &= ~(1 << rLR);
1950 cUnit->coreSpillMask |= (1 << rPC);
1951 }
1952 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1953 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1954 /* We didn't pop to rPC, so must do a bv rLR */
1955 newLIR1(cUnit, kThumbBx, rLR);
1956 }
1957 }
1958
1959 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1960
1961 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07001962 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1963 oatClobberAllRegs(cUnit);
1964 }
buzbee67bf8852011-08-17 17:51:35 -07001965
1966 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1967 oatResetDefTracking(cUnit);
1968 }
1969
1970 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1971 handleExtendedMethodMIR(cUnit, mir);
1972 continue;
1973 }
1974
1975 cUnit->currentDalvikOffset = mir->offset;
1976
1977 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1978 InstructionFormat dalvikFormat =
1979 dexGetFormatFromOpcode(dalvikOpcode);
1980
1981 ArmLIR* boundaryLIR;
1982
1983 /* Mark the beginning of a Dalvik instruction for line tracking */
buzbee5abfa3e2012-01-31 17:01:43 -08001984 char* instStr = cUnit->printMe ?
buzbeeba938cb2012-02-03 14:47:55 -08001985 oatGetDalvikDisassembly(cUnit, &mir->dalvikInsn, "") : NULL;
buzbee67bf8852011-08-17 17:51:35 -07001986 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
buzbee5abfa3e2012-01-31 17:01:43 -08001987 (intptr_t) instStr);
buzbee85d8c1e2012-01-27 15:52:35 -08001988 cUnit->boundaryMap.insert(std::make_pair(mir->offset,
1989 (LIR*)boundaryLIR));
buzbee67bf8852011-08-17 17:51:35 -07001990 /* Remember the first LIR for this block */
1991 if (headLIR == NULL) {
1992 headLIR = boundaryLIR;
1993 /* Set the first boundaryLIR as a scheduling barrier */
1994 headLIR->defMask = ENCODE_ALL;
1995 }
1996
1997 /* Don't generate the SSA annotation unless verbose mode is on */
1998 if (cUnit->printMe && mir->ssaRep) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -08001999 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
buzbee67bf8852011-08-17 17:51:35 -07002000 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
2001 }
2002
2003 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
2004
2005 if (notHandled) {
2006 char buf[100];
2007 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
2008 mir->offset,
2009 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
2010 dalvikFormat);
2011 LOG(FATAL) << buf;
2012 }
2013 }
2014
2015 if (headLIR) {
2016 /*
2017 * Eliminate redundant loads/stores and delay stores into later
2018 * slots
2019 */
2020 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
2021 cUnit->lastLIRInsn);
2022
2023 /*
2024 * Generate an unconditional branch to the fallthrough block.
2025 */
2026 if (bb->fallThrough) {
2027 genUnconditionalBranch(cUnit,
2028 &labelList[bb->fallThrough->id]);
2029 }
2030 }
2031 return false;
2032}
2033
2034/*
2035 * Nop any unconditional branches that go to the next instruction.
2036 * Note: new redundant branches may be inserted later, and we'll
2037 * use a check in final instruction assembly to nop those out.
2038 */
2039void removeRedundantBranches(CompilationUnit* cUnit)
2040{
2041 ArmLIR* thisLIR;
2042
2043 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2044 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2045 thisLIR = NEXT_LIR(thisLIR)) {
2046
2047 /* Branch to the next instruction */
2048 if ((thisLIR->opcode == kThumbBUncond) ||
2049 (thisLIR->opcode == kThumb2BUncond)) {
2050 ArmLIR* nextLIR = thisLIR;
2051
2052 while (true) {
2053 nextLIR = NEXT_LIR(nextLIR);
2054
2055 /*
2056 * Is the branch target the next instruction?
2057 */
2058 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2059 thisLIR->flags.isNop = true;
2060 break;
2061 }
2062
2063 /*
2064 * Found real useful stuff between the branch and the target.
2065 * Need to explicitly check the lastLIRInsn here because it
2066 * might be the last real instruction.
2067 */
2068 if (!isPseudoOpcode(nextLIR->opcode) ||
2069 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2070 break;
2071 }
2072 }
2073 }
2074}
2075
buzbeeed3e9302011-09-23 17:34:19 -07002076STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002077{
2078 ArmLIR** suspendLabel =
2079 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2080 int numElems = cUnit->suspendLaunchpads.numUsed;
2081
2082 for (int i = 0; i < numElems; i++) {
2083 /* TUNING: move suspend count load into helper */
2084 ArmLIR* lab = suspendLabel[i];
2085 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2086 cUnit->currentDalvikOffset = lab->operands[1];
2087 oatAppendLIR(cUnit, (LIR *)lab);
2088 loadWordDisp(cUnit, rSELF,
2089 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2090 loadWordDisp(cUnit, rSELF,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002091 Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
buzbeec1f45042011-09-21 16:03:19 -07002092 opReg(cUnit, kOpBlx, rLR);
2093 genUnconditionalBranch(cUnit, resumeLab);
2094 }
2095}
2096
buzbeeed3e9302011-09-23 17:34:19 -07002097STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002098{
2099 ArmLIR** throwLabel =
2100 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2101 int numElems = cUnit->throwLaunchpads.numUsed;
2102 int i;
2103
2104 for (i = 0; i < numElems; i++) {
2105 ArmLIR* lab = throwLabel[i];
2106 cUnit->currentDalvikOffset = lab->operands[1];
2107 oatAppendLIR(cUnit, (LIR *)lab);
2108 int funcOffset = 0;
2109 int v1 = lab->operands[2];
2110 int v2 = lab->operands[3];
2111 switch(lab->operands[0]) {
2112 case kArmThrowNullPointer:
2113 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2114 break;
2115 case kArmThrowArrayBounds:
2116 if (v2 != r0) {
2117 genRegCopy(cUnit, r0, v1);
2118 genRegCopy(cUnit, r1, v2);
2119 } else {
2120 if (v1 == r1) {
2121 genRegCopy(cUnit, r12, v1);
2122 genRegCopy(cUnit, r1, v2);
2123 genRegCopy(cUnit, r0, r12);
2124 } else {
2125 genRegCopy(cUnit, r1, v2);
2126 genRegCopy(cUnit, r0, v1);
2127 }
2128 }
2129 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2130 break;
2131 case kArmThrowDivZero:
2132 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2133 break;
2134 case kArmThrowVerificationError:
2135 loadConstant(cUnit, r0, v1);
2136 loadConstant(cUnit, r1, v2);
2137 funcOffset =
2138 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2139 break;
2140 case kArmThrowNegArraySize:
2141 genRegCopy(cUnit, r0, v1);
2142 funcOffset =
2143 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2144 break;
buzbee5ade1d22011-09-09 14:44:52 -07002145 case kArmThrowNoSuchMethod:
buzbee13ac45a2012-01-12 12:30:16 -08002146 genRegCopy(cUnit, r0, v1);
buzbee5ade1d22011-09-09 14:44:52 -07002147 funcOffset =
2148 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2149 break;
buzbeeec5adf32011-09-11 15:25:43 -07002150 case kArmThrowStackOverflow:
2151 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002152 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002153 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002154 opRegImm(cUnit, kOpAdd, rSP,
2155 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002156 break;
buzbee5ade1d22011-09-09 14:44:52 -07002157 default:
2158 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2159 }
2160 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002161 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002162 }
2163}
2164
buzbee67bf8852011-08-17 17:51:35 -07002165void oatMethodMIR2LIR(CompilationUnit* cUnit)
2166{
2167 /* Used to hold the labels of each block */
2168 cUnit->blockLabelList =
buzbeeba938cb2012-02-03 14:47:55 -08002169 (void *) oatNew(cUnit, sizeof(ArmLIR) * cUnit->numBlocks, true,
2170 kAllocLIR);
buzbee67bf8852011-08-17 17:51:35 -07002171
2172 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2173 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002174 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002175
2176 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002177
2178 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002179}
2180
2181/* Common initialization routine for an architecture family */
2182bool oatArchInit()
2183{
2184 int i;
2185
2186 for (i = 0; i < kArmLast; i++) {
2187 if (EncodingMap[i].opcode != i) {
2188 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2189 " is wrong: expecting " << i << ", seeing " <<
2190 (int)EncodingMap[i].opcode;
2191 }
2192 }
2193
2194 return oatArchVariantInit();
2195}
2196
2197/* Needed by the Assembler */
2198void oatSetupResourceMasks(ArmLIR* lir)
2199{
2200 setupResourceMasks(lir);
2201}
2202
2203/* Needed by the ld/st optmizatons */
2204ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2205{
2206 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2207}
2208
2209/* Needed by the register allocator */
2210ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2211{
2212 return genRegCopy(cUnit, rDest, rSrc);
2213}
2214
2215/* Needed by the register allocator */
2216void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2217 int srcLo, int srcHi)
2218{
2219 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2220}
2221
2222void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2223 int displacement, int rSrc, OpSize size)
2224{
2225 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2226}
2227
2228void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2229 int displacement, int rSrcLo, int rSrcHi)
2230{
2231 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2232}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002233
2234} // namespace art