blob: eb2c06b2b0817c9d6a5268c7671c3c20130500c3 [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
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800354typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
355 uint32_t methodIdx);
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,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800362 int state, uint32_t dexIdx, uint32_t unused)
buzbee67bf8852011-08-17 17:51:35 -0700363{
364 switch(state) {
365 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700366 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700367 break;
buzbee561227c2011-09-02 15:28:19 -0700368 case 1: // Get method->code_and_direct_methods_
369 loadWordDisp(cUnit, r0,
370 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
371 r0);
buzbee67bf8852011-08-17 17:51:35 -0700372 break;
buzbee561227c2011-09-02 15:28:19 -0700373 case 2: // Grab target method* and target code_
374 loadWordDisp(cUnit, r0,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800375 CodeAndDirectMethods::CodeOffsetInBytes(dexIdx), rLR);
buzbee561227c2011-09-02 15:28:19 -0700376 loadWordDisp(cUnit, r0,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800377 CodeAndDirectMethods::MethodOffsetInBytes(dexIdx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700378 break;
379 default:
380 return -1;
381 }
382 return state + 1;
383}
384
buzbee67bf8852011-08-17 17:51:35 -0700385/*
386 * Bit of a hack here - in leiu of a real scheduling pass,
387 * emit the next instruction in a virtual invoke sequence.
388 * We can use rLR as a temp prior to target address loading
389 * Note also that we'll load the first argument ("this") into
390 * r1 here rather than the standard loadArgRegs.
391 */
buzbeeed3e9302011-09-23 17:34:19 -0700392STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800393 int state, uint32_t dexIdx, uint32_t methodIdx)
buzbee67bf8852011-08-17 17:51:35 -0700394{
395 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700396 /*
397 * This is the fast path in which the target virtual method is
398 * fully resolved at compile time.
399 */
buzbee67bf8852011-08-17 17:51:35 -0700400 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700401 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700402 rlArg = oatGetSrc(cUnit, mir, 0);
403 loadValueDirectFixed(cUnit, rlArg, r1);
404 break;
buzbee561227c2011-09-02 15:28:19 -0700405 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700406 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700407 // get this->klass_ [use r1, set rLR]
408 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700409 break;
buzbee561227c2011-09-02 15:28:19 -0700410 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
411 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700412 break;
buzbee561227c2011-09-02 15:28:19 -0700413 case 3: // Get target method [use rLR, set r0]
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800414 loadWordDisp(cUnit, rLR, (methodIdx * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800415 Array::DataOffset().Int32Value(), r0);
buzbee561227c2011-09-02 15:28:19 -0700416 break;
417 case 4: // Get the target compiled code address [uses r0, sets rLR]
418 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700419 break;
420 default:
421 return -1;
422 }
423 return state + 1;
424}
425
buzbee67bf8852011-08-17 17:51:35 -0700426/*
427 * Interleave launch code for INVOKE_SUPER. See comments
428 * for nextVCallIns.
429 */
buzbeeed3e9302011-09-23 17:34:19 -0700430STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800431 int state, uint32_t dexIdx, uint32_t methodIdx)
buzbee67bf8852011-08-17 17:51:35 -0700432{
buzbee4a3164f2011-09-03 11:25:10 -0700433 /*
434 * This is the fast path in which the target virtual method is
435 * fully resolved at compile time. Note also that this path assumes
436 * that the check to verify that the target method index falls
437 * within the size of the super's vtable has been done at compile-time.
438 */
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800439 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700440 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700441 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700442 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700443 // Load "this" [set r1]
444 rlArg = oatGetSrc(cUnit, mir, 0);
445 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700446 // Get method->declaring_class_ [use r0, set rLR]
447 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
448 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700449 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700450 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700451 break;
452 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
453 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
454 rLR);
455 break;
456 case 2: // Get ...->super_class_->vtable [u/s rLR]
457 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
458 break;
459 case 3: // Get target method [use rLR, set r0]
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800460 loadWordDisp(cUnit, rLR, (methodIdx * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800461 Array::DataOffset().Int32Value(), r0);
buzbee4a3164f2011-09-03 11:25:10 -0700462 break;
463 case 4: // Get the target compiled code address [uses r0, sets rLR]
464 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
465 break;
buzbee67bf8852011-08-17 17:51:35 -0700466 default:
467 return -1;
468 }
buzbee4a3164f2011-09-03 11:25:10 -0700469 return state + 1;
470}
471
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800472STATIC int nextInvokeInsnSP(CompilationUnit* cUnit, MIR* mir,
473 bool accessCheck, bool isInterface,
474 bool isSuper, int state, uint32_t dexIdx,
475 uint32_t methodIdx)
buzbee4a3164f2011-09-03 11:25:10 -0700476{
buzbee4a3164f2011-09-03 11:25:10 -0700477 /*
478 * This handles the case in which the base method is not fully
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800479 * resolved at compile time, we bail to a runtime helper.
buzbee4a3164f2011-09-03 11:25:10 -0700480 */
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800481 if (state == 0) {
482 int trampoline;
483 if (!accessCheck) {
484 DCHECK(isInterface);
485 trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
486 } else {
487 if (isInterface) {
488 trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
489 } else if (isSuper) {
490 trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
491 } else {
492 trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
493 }
494 }
495 // Load trampoline target
496 loadWordDisp(cUnit, rSELF, trampoline, rLR);
497 // Load r0 with method index
498 loadConstant(cUnit, r0, dexIdx);
499 return 1;
buzbee4a3164f2011-09-03 11:25:10 -0700500 }
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800501 return -1;
502}
503
504STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
505 int state, uint32_t dexIdx, uint32_t methodIdx)
506{
507 return nextInvokeInsnSP(cUnit, mir, true, false, true, state, dexIdx,
508 methodIdx);
509}
510
511STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
512 int state, uint32_t dexIdx, uint32_t methodIdx)
513{
514 return nextInvokeInsnSP(cUnit, mir, true, false, false, state, dexIdx,
515 methodIdx);
516}
517
518/*
519 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
520 * which will locate the target and continue on via a tail call.
521 */
522STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
523 int state, uint32_t dexIdx, uint32_t unused)
524{
525 return nextInvokeInsnSP(cUnit, mir, false, true, false, state, dexIdx, 0);
526}
527
528STATIC int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
529 MIR* mir, int state,
530 uint32_t dexIdx,
531 uint32_t unused)
532{
533 return nextInvokeInsnSP(cUnit, mir, true, true, false, state, dexIdx, 0);
534}
535
536STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
537 DecodedInstruction* dInsn, int callState,
538 NextCallInsn nextCallInsn, uint32_t dexIdx,
539 uint32_t methodIdx, bool skipThis)
540{
541 int nextReg = r1;
542 int nextArg = 0;
543 if (skipThis) {
544 nextReg++;
545 nextArg++;
546 }
547 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
548 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
549 rlArg = oatUpdateRawLoc(cUnit, rlArg);
550 if (rlArg.wide && (nextReg <= r2)) {
551 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
552 nextReg++;
553 nextArg++;
554 } else {
555 rlArg.wide = false;
556 loadValueDirectFixed(cUnit, rlArg, nextReg);
557 }
558 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
559 }
560 return callState;
buzbee67bf8852011-08-17 17:51:35 -0700561}
562
563/*
564 * Load up to 5 arguments, the first three of which will be in
565 * r1 .. r3. On entry r0 contains the current method pointer,
566 * and as part of the load sequence, it must be replaced with
567 * the target method pointer. Note, this may also be called
568 * for "range" variants if the number of arguments is 5 or fewer.
569 */
buzbeeed3e9302011-09-23 17:34:19 -0700570STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700571 DecodedInstruction* dInsn, int callState,
572 ArmLIR** pcrLabel, bool isRange,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800573 NextCallInsn nextCallInsn, uint32_t dexIdx,
574 uint32_t methodIdx, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700575{
576 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700577
578 /* If no arguments, just return */
579 if (dInsn->vA == 0)
580 return callState;
581
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800582 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
buzbee67bf8852011-08-17 17:51:35 -0700583
buzbeec0ecd652011-09-25 18:11:54 -0700584 DCHECK_LE(dInsn->vA, 5U);
585 if (dInsn->vA > 3) {
586 uint32_t nextUse = 3;
587 //Detect special case of wide arg spanning arg3/arg4
588 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
589 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
590 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
591 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
592 rlUse2.wide) {
593 int reg;
594 // Wide spans, we need the 2nd half of uses[2].
595 rlArg = oatUpdateLocWide(cUnit, rlUse2);
596 if (rlArg.location == kLocPhysReg) {
597 reg = rlArg.highReg;
598 } else {
599 // r2 & r3 can safely be used here
600 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700601 loadWordDisp(cUnit, rSP,
602 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800603 callState = nextCallInsn(cUnit, mir, callState, dexIdx,
604 methodIdx);
buzbeec0ecd652011-09-25 18:11:54 -0700605 }
606 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
607 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800608 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
buzbeec0ecd652011-09-25 18:11:54 -0700609 nextUse++;
610 }
611 // Loop through the rest
612 while (nextUse < dInsn->vA) {
613 int lowReg;
614 int highReg;
615 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
616 rlArg = oatUpdateRawLoc(cUnit, rlArg);
617 if (rlArg.location == kLocPhysReg) {
618 lowReg = rlArg.lowReg;
619 highReg = rlArg.highReg;
620 } else {
621 lowReg = r2;
622 highReg = r3;
623 if (rlArg.wide) {
624 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
625 } else {
626 loadValueDirectFixed(cUnit, rlArg, lowReg);
627 }
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800628 callState = nextCallInsn(cUnit, mir, callState, dexIdx,
629 methodIdx);
buzbeec0ecd652011-09-25 18:11:54 -0700630 }
631 int outsOffset = (nextUse + 1) * 4;
632 if (rlArg.wide) {
633 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
634 nextUse += 2;
635 } else {
636 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
637 nextUse++;
638 }
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800639 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
buzbee67bf8852011-08-17 17:51:35 -0700640 }
buzbee67bf8852011-08-17 17:51:35 -0700641 }
642
buzbeec0ecd652011-09-25 18:11:54 -0700643 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800644 dexIdx, methodIdx, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700645
buzbee67bf8852011-08-17 17:51:35 -0700646 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700647 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700648 }
649 return callState;
650}
651
652/*
653 * May have 0+ arguments (also used for jumbo). Note that
654 * source virtual registers may be in physical registers, so may
655 * need to be flushed to home location before copying. This
656 * applies to arg3 and above (see below).
657 *
658 * Two general strategies:
659 * If < 20 arguments
660 * Pass args 3-18 using vldm/vstm block copy
661 * Pass arg0, arg1 & arg2 in r1-r3
662 * If 20+ arguments
663 * Pass args arg19+ using memcpy block copy
664 * Pass arg0, arg1 & arg2 in r1-r3
665 *
666 */
buzbeeed3e9302011-09-23 17:34:19 -0700667STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700668 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700669 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800670 uint32_t dexIdx, uint32_t methodIdx,
671 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700672{
673 int firstArg = dInsn->vC;
674 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700675
buzbee67bf8852011-08-17 17:51:35 -0700676 // If we can treat it as non-range (Jumbo ops will use range form)
677 if (numArgs <= 5)
678 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800679 true, nextCallInsn, dexIdx, methodIdx,
680 skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700681 /*
682 * Make sure range list doesn't span the break between in normal
683 * Dalvik vRegs and the ins.
684 */
buzbee1b4c8592011-08-31 10:43:51 -0700685 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800686 int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee1b4c8592011-08-31 10:43:51 -0700687 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
688 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700689 }
690
691 /*
692 * First load the non-register arguments. Both forms expect all
693 * of the source arguments to be in their home frame location, so
694 * scan the sReg names and flush any that have been promoted to
695 * frame backing storage.
696 */
697 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700698 for (int nextArg = 0; nextArg < numArgs;) {
699 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700700 if (loc.wide) {
701 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700702 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700703 storeBaseDispWide(cUnit, rSP,
704 oatSRegOffset(cUnit, loc.sRegLow),
705 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700706 }
buzbeec0ecd652011-09-25 18:11:54 -0700707 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700708 } else {
709 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700710 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700711 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
712 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700713 }
buzbeec0ecd652011-09-25 18:11:54 -0700714 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700715 }
716 }
717
buzbee67bc2362011-10-11 18:08:40 -0700718 int startOffset = oatSRegOffset(cUnit,
719 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700720 int outsOffset = 4 /* Method* */ + (3 * 4);
721 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700722 // Generate memcpy
723 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
724 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700725 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
726 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700727 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700728 // Restore Method*
729 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700730 } else {
731 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700732 int regsLeft = std::min(numArgs - 3, 16);
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800733 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
buzbee67bf8852011-08-17 17:51:35 -0700734 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700735 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
736 //TUNING: loosen barrier
737 ld->defMask = ENCODE_ALL;
738 setMemRefType(ld, true /* isLoad */, kDalvikReg);
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800739 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
buzbee67bf8852011-08-17 17:51:35 -0700740 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800741 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
buzbeef48e9712011-09-15 17:54:28 -0700742 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
743 setMemRefType(st, false /* isLoad */, kDalvikReg);
744 st->defMask = ENCODE_ALL;
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800745 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
buzbee67bf8852011-08-17 17:51:35 -0700746 }
747
buzbeec0ecd652011-09-25 18:11:54 -0700748 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800749 dexIdx, methodIdx, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700750
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800751 callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx);
buzbee99f27232011-10-05 12:56:36 -0700752 if (pcrLabel) {
753 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
754 }
buzbee67bf8852011-08-17 17:51:35 -0700755 return callState;
756}
757
buzbee2a475e72011-09-07 17:19:17 -0700758// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700759STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700760{
761 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
762 loadWordDisp(cUnit, rSELF,
763 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
764 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
765 target->defMask = -1;
766 branchOver->generic.target = (LIR*)target;
767}
buzbee2a475e72011-09-07 17:19:17 -0700768
buzbeeed3e9302011-09-23 17:34:19 -0700769STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700770 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700771{
772 DecodedInstruction* dInsn = &mir->dalvikInsn;
773 int callState = 0;
774 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700775 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700776 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700777 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700778
buzbee109bd6a2011-09-06 13:58:41 -0700779 // Explicit register usage
780 oatLockCallTemps(cUnit);
781
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800782 uint32_t dexMethodIdx = mir->dalvikInsn.vB;
buzbee99f27232011-10-05 12:56:36 -0700783 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800784 if (direct && !range) {
785 Method* target = cUnit->dex_cache->GetResolvedMethods()->Get(dexMethodIdx);
buzbee99f27232011-10-05 12:56:36 -0700786 if (target) {
787 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
788 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
789 loadValueDirectFixed(cUnit, rlArg, r0);
790 loadWordDisp(cUnit, rSELF,
791 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
792 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
793 opReg(cUnit, kOpBlx, rLR);
794 oatClobberCalleeSave(cUnit);
795 return;
796 }
797 }
798 }
799
buzbee561227c2011-09-02 15:28:19 -0700800 if (range) {
801 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800802 nextCallInsn, dexMethodIdx, 0, false);
buzbee561227c2011-09-02 15:28:19 -0700803 } else {
804 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800805 false, nextCallInsn, dexMethodIdx,
806 0, false);
buzbee561227c2011-09-02 15:28:19 -0700807 }
buzbee67bf8852011-08-17 17:51:35 -0700808 // Finish up any of the call sequence not interleaved in arg loading
809 while (callState >= 0) {
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800810 callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx, 0);
buzbee67bf8852011-08-17 17:51:35 -0700811 }
buzbeece302932011-10-04 14:32:18 -0700812 if (DISPLAY_MISSING_TARGETS) {
813 genShowTarget(cUnit);
814 }
buzbeeec5adf32011-09-11 15:25:43 -0700815 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700816 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700817}
818
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800819STATIC void genInvoke(CompilationUnit* cUnit, MIR* mir, bool isInterface,
820 bool isSuper, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -0700821{
822 DecodedInstruction* dInsn = &mir->dalvikInsn;
823 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -0700824 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700825 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -0700826 // Explicit register usage
827 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -0800828
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800829 uint32_t dexMethodIdx = dInsn->vB;
830 int vtableIdx;
831 bool fastPath =
832 cUnit->compiler->ComputeInvokeInfo(dexMethodIdx, cUnit,
833 isInterface, isSuper, vtableIdx)
834 && !SLOW_INVOKE_PATH;
835 if (isInterface) {
836 nextCallInsn = fastPath ? nextInterfaceCallInsn
837 : nextInterfaceCallInsnWithAccessCheck;
838 } else if (isSuper) {
839 nextCallInsn = fastPath ? nextSuperCallInsn : nextSuperCallInsnSP;
buzbee561227c2011-09-02 15:28:19 -0700840 } else {
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800841 nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
buzbee561227c2011-09-02 15:28:19 -0700842 }
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800843 bool skipThis = fastPath && !isInterface;
844 if (!isRange) {
buzbeec0ecd652011-09-25 18:11:54 -0700845 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800846 false, nextCallInsn, dexMethodIdx,
847 vtableIdx, skipThis);
848 } else {
buzbeec0ecd652011-09-25 18:11:54 -0700849 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800850 nextCallInsn, dexMethodIdx, vtableIdx,
851 skipThis);
852 }
buzbee67bf8852011-08-17 17:51:35 -0700853 // Finish up any of the call sequence not interleaved in arg loading
854 while (callState >= 0) {
Ian Rogersa32a6fd2012-02-06 20:18:44 -0800855 callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
856 vtableIdx);
buzbee67bf8852011-08-17 17:51:35 -0700857 }
buzbeece302932011-10-04 14:32:18 -0700858 if (DISPLAY_MISSING_TARGETS) {
859 genShowTarget(cUnit);
860 }
buzbeeec5adf32011-09-11 15:25:43 -0700861 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700862 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700863}
864
buzbeeed3e9302011-09-23 17:34:19 -0700865STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700866 BasicBlock* bb, ArmLIR* labelList)
867{
868 bool res = false; // Assume success
869 RegLocation rlSrc[3];
870 RegLocation rlDest = badLoc;
871 RegLocation rlResult = badLoc;
872 Opcode opcode = mir->dalvikInsn.opcode;
873
874 /* Prep Src and Dest locations */
875 int nextSreg = 0;
876 int nextLoc = 0;
877 int attrs = oatDataFlowAttributes[opcode];
878 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
879 if (attrs & DF_UA) {
880 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
881 nextSreg++;
882 } else if (attrs & DF_UA_WIDE) {
883 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
884 nextSreg + 1);
885 nextSreg+= 2;
886 }
887 if (attrs & DF_UB) {
888 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
889 nextSreg++;
890 } else if (attrs & DF_UB_WIDE) {
891 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
892 nextSreg + 1);
893 nextSreg+= 2;
894 }
895 if (attrs & DF_UC) {
896 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
897 } else if (attrs & DF_UC_WIDE) {
898 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
899 nextSreg + 1);
900 }
901 if (attrs & DF_DA) {
902 rlDest = oatGetDest(cUnit, mir, 0);
903 } else if (attrs & DF_DA_WIDE) {
904 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
905 }
906
907 switch(opcode) {
908 case OP_NOP:
909 break;
910
911 case OP_MOVE_EXCEPTION:
912 int exOffset;
913 int resetReg;
buzbeec143c552011-08-20 17:38:58 -0700914 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -0700915 resetReg = oatAllocTemp(cUnit);
916 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
917 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
918 loadConstant(cUnit, resetReg, 0);
919 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
920 storeValue(cUnit, rlDest, rlResult);
921 break;
922
923 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -0700924 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -0700925 break;
926
927 case OP_RETURN:
928 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -0700929 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -0700930 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -0700931 break;
932
933 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -0700934 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -0700935 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -0700936 break;
937
938 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -0700939 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -0700940 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -0700941 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -0700942 break;
943
944 case OP_MOVE_RESULT:
945 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -0700946 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -0700947 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -0700948 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -0700949 break;
950
951 case OP_MOVE:
952 case OP_MOVE_OBJECT:
953 case OP_MOVE_16:
954 case OP_MOVE_OBJECT_16:
955 case OP_MOVE_FROM16:
956 case OP_MOVE_OBJECT_FROM16:
957 storeValue(cUnit, rlDest, rlSrc[0]);
958 break;
959
960 case OP_MOVE_WIDE:
961 case OP_MOVE_WIDE_16:
962 case OP_MOVE_WIDE_FROM16:
963 storeValueWide(cUnit, rlDest, rlSrc[0]);
964 break;
965
966 case OP_CONST:
967 case OP_CONST_4:
968 case OP_CONST_16:
969 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
970 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
971 storeValue(cUnit, rlDest, rlResult);
972 break;
973
974 case OP_CONST_HIGH16:
975 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
976 loadConstantNoClobber(cUnit, rlResult.lowReg,
977 mir->dalvikInsn.vB << 16);
978 storeValue(cUnit, rlDest, rlResult);
979 break;
980
981 case OP_CONST_WIDE_16:
982 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -0700983 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
984 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
985 mir->dalvikInsn.vB,
986 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -0700987 storeValueWide(cUnit, rlDest, rlResult);
988 break;
989
990 case OP_CONST_WIDE:
991 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
992 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -0700993 mir->dalvikInsn.vB_wide & 0xffffffff,
994 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -0700995 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -0700996 break;
997
998 case OP_CONST_WIDE_HIGH16:
999 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1000 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1001 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001002 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001003 break;
1004
1005 case OP_MONITOR_ENTER:
1006 genMonitorEnter(cUnit, mir, rlSrc[0]);
1007 break;
1008
1009 case OP_MONITOR_EXIT:
1010 genMonitorExit(cUnit, mir, rlSrc[0]);
1011 break;
1012
1013 case OP_CHECK_CAST:
1014 genCheckCast(cUnit, mir, rlSrc[0]);
1015 break;
1016
1017 case OP_INSTANCE_OF:
1018 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1019 break;
1020
1021 case OP_NEW_INSTANCE:
1022 genNewInstance(cUnit, mir, rlDest);
1023 break;
1024
1025 case OP_THROW:
1026 genThrow(cUnit, mir, rlSrc[0]);
1027 break;
1028
buzbee5ade1d22011-09-09 14:44:52 -07001029 case OP_THROW_VERIFICATION_ERROR:
1030 loadWordDisp(cUnit, rSELF,
1031 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1032 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1033 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001034 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001035 break;
1036
buzbee67bf8852011-08-17 17:51:35 -07001037 case OP_ARRAY_LENGTH:
1038 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001039 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001040 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001041 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001042 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1043 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1044 rlResult.lowReg);
1045 storeValue(cUnit, rlDest, rlResult);
1046 break;
1047
1048 case OP_CONST_STRING:
1049 case OP_CONST_STRING_JUMBO:
1050 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1051 break;
1052
1053 case OP_CONST_CLASS:
1054 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1055 break;
1056
1057 case OP_FILL_ARRAY_DATA:
1058 genFillArrayData(cUnit, mir, rlSrc[0]);
1059 break;
1060
1061 case OP_FILLED_NEW_ARRAY:
1062 genFilledNewArray(cUnit, mir, false /* not range */);
1063 break;
1064
1065 case OP_FILLED_NEW_ARRAY_RANGE:
1066 genFilledNewArray(cUnit, mir, true /* range */);
1067 break;
1068
1069 case OP_NEW_ARRAY:
1070 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1071 break;
1072
1073 case OP_GOTO:
1074 case OP_GOTO_16:
1075 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001076 if (bb->taken->startOffset <= mir->offset) {
1077 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001078 }
1079 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1080 break;
1081
1082 case OP_PACKED_SWITCH:
1083 genPackedSwitch(cUnit, mir, rlSrc[0]);
1084 break;
1085
1086 case OP_SPARSE_SWITCH:
1087 genSparseSwitch(cUnit, mir, rlSrc[0]);
1088 break;
1089
1090 case OP_CMPL_FLOAT:
1091 case OP_CMPG_FLOAT:
1092 case OP_CMPL_DOUBLE:
1093 case OP_CMPG_DOUBLE:
1094 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1095 break;
1096
1097 case OP_CMP_LONG:
1098 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1099 break;
1100
1101 case OP_IF_EQ:
1102 case OP_IF_NE:
1103 case OP_IF_LT:
1104 case OP_IF_GE:
1105 case OP_IF_GT:
1106 case OP_IF_LE: {
1107 bool backwardBranch;
1108 ArmConditionCode cond;
1109 backwardBranch = (bb->taken->startOffset <= mir->offset);
1110 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001111 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001112 }
1113 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1114 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1115 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1116 switch(opcode) {
1117 case OP_IF_EQ:
1118 cond = kArmCondEq;
1119 break;
1120 case OP_IF_NE:
1121 cond = kArmCondNe;
1122 break;
1123 case OP_IF_LT:
1124 cond = kArmCondLt;
1125 break;
1126 case OP_IF_GE:
1127 cond = kArmCondGe;
1128 break;
1129 case OP_IF_GT:
1130 cond = kArmCondGt;
1131 break;
1132 case OP_IF_LE:
1133 cond = kArmCondLe;
1134 break;
1135 default:
1136 cond = (ArmConditionCode)0;
1137 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1138 }
1139 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1140 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1141 break;
1142 }
1143
1144 case OP_IF_EQZ:
1145 case OP_IF_NEZ:
1146 case OP_IF_LTZ:
1147 case OP_IF_GEZ:
1148 case OP_IF_GTZ:
1149 case OP_IF_LEZ: {
1150 bool backwardBranch;
1151 ArmConditionCode cond;
1152 backwardBranch = (bb->taken->startOffset <= mir->offset);
1153 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001154 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001155 }
1156 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1157 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1158 switch(opcode) {
1159 case OP_IF_EQZ:
1160 cond = kArmCondEq;
1161 break;
1162 case OP_IF_NEZ:
1163 cond = kArmCondNe;
1164 break;
1165 case OP_IF_LTZ:
1166 cond = kArmCondLt;
1167 break;
1168 case OP_IF_GEZ:
1169 cond = kArmCondGe;
1170 break;
1171 case OP_IF_GTZ:
1172 cond = kArmCondGt;
1173 break;
1174 case OP_IF_LEZ:
1175 cond = kArmCondLe;
1176 break;
1177 default:
1178 cond = (ArmConditionCode)0;
1179 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1180 }
1181 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1182 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1183 break;
1184 }
1185
1186 case OP_AGET_WIDE:
1187 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1188 break;
1189 case OP_AGET:
1190 case OP_AGET_OBJECT:
1191 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1192 break;
1193 case OP_AGET_BOOLEAN:
1194 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1195 rlDest, 0);
1196 break;
1197 case OP_AGET_BYTE:
1198 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1199 break;
1200 case OP_AGET_CHAR:
1201 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1202 rlDest, 1);
1203 break;
1204 case OP_AGET_SHORT:
1205 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1206 break;
1207 case OP_APUT_WIDE:
1208 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1209 break;
1210 case OP_APUT:
1211 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1212 break;
1213 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001214 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001215 break;
1216 case OP_APUT_SHORT:
1217 case OP_APUT_CHAR:
1218 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1219 rlSrc[0], 1);
1220 break;
1221 case OP_APUT_BYTE:
1222 case OP_APUT_BOOLEAN:
1223 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1224 rlSrc[0], 0);
1225 break;
1226
Ian Rogers1bddec32012-02-04 12:27:34 -08001227 case OP_IGET_OBJECT:
1228 case OP_IGET_OBJECT_VOLATILE:
1229 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, true);
1230 break;
1231
buzbee67bf8852011-08-17 17:51:35 -07001232 case OP_IGET_WIDE:
1233 case OP_IGET_WIDE_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001234 genIGet(cUnit, mir, kLong, rlDest, rlSrc[0], true, false);
buzbee67bf8852011-08-17 17:51:35 -07001235 break;
1236
1237 case OP_IGET:
1238 case OP_IGET_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001239 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0], false, false);
1240 break;
1241
1242 case OP_IGET_CHAR:
1243 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0], false, false);
1244 break;
1245
1246 case OP_IGET_SHORT:
1247 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001248 break;
1249
1250 case OP_IGET_BOOLEAN:
1251 case OP_IGET_BYTE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001252 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001253 break;
1254
1255 case OP_IPUT_WIDE:
1256 case OP_IPUT_WIDE_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001257 genIPut(cUnit, mir, kLong, rlSrc[0], rlSrc[1], true, false);
buzbee67bf8852011-08-17 17:51:35 -07001258 break;
1259
1260 case OP_IPUT_OBJECT:
1261 case OP_IPUT_OBJECT_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001262 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, true);
buzbee67bf8852011-08-17 17:51:35 -07001263 break;
1264
1265 case OP_IPUT:
1266 case OP_IPUT_VOLATILE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001267 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001268 break;
1269
1270 case OP_IPUT_BOOLEAN:
1271 case OP_IPUT_BYTE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001272 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001273 break;
1274
1275 case OP_IPUT_CHAR:
Ian Rogers1bddec32012-02-04 12:27:34 -08001276 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001277 break;
1278
1279 case OP_IPUT_SHORT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001280 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001281 break;
1282
buzbee67bf8852011-08-17 17:51:35 -07001283 case OP_SGET_OBJECT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001284 genSget(cUnit, mir, rlDest, false, true);
1285 break;
1286 case OP_SGET:
buzbee67bf8852011-08-17 17:51:35 -07001287 case OP_SGET_BOOLEAN:
1288 case OP_SGET_BYTE:
1289 case OP_SGET_CHAR:
1290 case OP_SGET_SHORT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001291 genSget(cUnit, mir, rlDest, false, false);
buzbee67bf8852011-08-17 17:51:35 -07001292 break;
1293
1294 case OP_SGET_WIDE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001295 genSget(cUnit, mir, rlDest, true, false);
buzbee67bf8852011-08-17 17:51:35 -07001296 break;
1297
buzbee67bf8852011-08-17 17:51:35 -07001298 case OP_SPUT_OBJECT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001299 genSput(cUnit, mir, rlSrc[0], false, true);
1300 break;
1301
1302 case OP_SPUT:
buzbee67bf8852011-08-17 17:51:35 -07001303 case OP_SPUT_BOOLEAN:
1304 case OP_SPUT_BYTE:
1305 case OP_SPUT_CHAR:
1306 case OP_SPUT_SHORT:
Ian Rogers1bddec32012-02-04 12:27:34 -08001307 genSput(cUnit, mir, rlSrc[0], false, false);
buzbee67bf8852011-08-17 17:51:35 -07001308 break;
1309
1310 case OP_SPUT_WIDE:
Ian Rogers1bddec32012-02-04 12:27:34 -08001311 genSput(cUnit, mir, rlSrc[0], true, false);
buzbee67bf8852011-08-17 17:51:35 -07001312 break;
1313
1314 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001315 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1316 true /*range*/);
1317 break;
buzbee67bf8852011-08-17 17:51:35 -07001318 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001319 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1320 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001321 break;
1322
1323 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001324 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1325 false /*range*/);
1326 break;
buzbee67bf8852011-08-17 17:51:35 -07001327 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001328 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1329 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001330 break;
1331
1332 case OP_INVOKE_VIRTUAL:
Ian Rogersa32a6fd2012-02-06 20:18:44 -08001333 genInvoke(cUnit, mir, false /*interface*/, false /*super*/,
1334 false /*range*/);
1335 break;
buzbee67bf8852011-08-17 17:51:35 -07001336 case OP_INVOKE_VIRTUAL_RANGE:
Ian Rogersa32a6fd2012-02-06 20:18:44 -08001337 genInvoke(cUnit, mir, false /*interface*/, false /*super*/,
1338 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001339 break;
1340
1341 case OP_INVOKE_SUPER:
Ian Rogersa32a6fd2012-02-06 20:18:44 -08001342 genInvoke(cUnit, mir, false /*interface*/, true /*super*/,
1343 false /*range*/);
1344 break;
buzbee67bf8852011-08-17 17:51:35 -07001345 case OP_INVOKE_SUPER_RANGE:
Ian Rogersa32a6fd2012-02-06 20:18:44 -08001346 genInvoke(cUnit, mir, false /*interface*/, true /*super*/,
1347 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001348 break;
1349
1350 case OP_INVOKE_INTERFACE:
Ian Rogersa32a6fd2012-02-06 20:18:44 -08001351 genInvoke(cUnit, mir, true /*interface*/, false /*super*/,
1352 false /*range*/);
1353 break;
buzbee67bf8852011-08-17 17:51:35 -07001354 case OP_INVOKE_INTERFACE_RANGE:
Ian Rogersa32a6fd2012-02-06 20:18:44 -08001355 genInvoke(cUnit, mir, true /*interface*/, false /*super*/,
1356 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001357 break;
1358
1359 case OP_NEG_INT:
1360 case OP_NOT_INT:
1361 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1362 break;
1363
1364 case OP_NEG_LONG:
1365 case OP_NOT_LONG:
1366 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1367 break;
1368
1369 case OP_NEG_FLOAT:
1370 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1371 break;
1372
1373 case OP_NEG_DOUBLE:
1374 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1375 break;
1376
1377 case OP_INT_TO_LONG:
1378 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1379 if (rlSrc[0].location == kLocPhysReg) {
1380 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1381 } else {
1382 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1383 }
1384 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1385 rlResult.lowReg, 31);
1386 storeValueWide(cUnit, rlDest, rlResult);
1387 break;
1388
1389 case OP_LONG_TO_INT:
1390 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1391 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1392 storeValue(cUnit, rlDest, rlSrc[0]);
1393 break;
1394
1395 case OP_INT_TO_BYTE:
1396 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1397 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1398 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1399 storeValue(cUnit, rlDest, rlResult);
1400 break;
1401
1402 case OP_INT_TO_SHORT:
1403 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1404 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1405 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1406 storeValue(cUnit, rlDest, rlResult);
1407 break;
1408
1409 case OP_INT_TO_CHAR:
1410 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1411 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1412 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1413 storeValue(cUnit, rlDest, rlResult);
1414 break;
1415
1416 case OP_INT_TO_FLOAT:
1417 case OP_INT_TO_DOUBLE:
1418 case OP_LONG_TO_FLOAT:
1419 case OP_LONG_TO_DOUBLE:
1420 case OP_FLOAT_TO_INT:
1421 case OP_FLOAT_TO_LONG:
1422 case OP_FLOAT_TO_DOUBLE:
1423 case OP_DOUBLE_TO_INT:
1424 case OP_DOUBLE_TO_LONG:
1425 case OP_DOUBLE_TO_FLOAT:
1426 genConversion(cUnit, mir);
1427 break;
1428
1429 case OP_ADD_INT:
1430 case OP_SUB_INT:
1431 case OP_MUL_INT:
1432 case OP_DIV_INT:
1433 case OP_REM_INT:
1434 case OP_AND_INT:
1435 case OP_OR_INT:
1436 case OP_XOR_INT:
1437 case OP_SHL_INT:
1438 case OP_SHR_INT:
1439 case OP_USHR_INT:
1440 case OP_ADD_INT_2ADDR:
1441 case OP_SUB_INT_2ADDR:
1442 case OP_MUL_INT_2ADDR:
1443 case OP_DIV_INT_2ADDR:
1444 case OP_REM_INT_2ADDR:
1445 case OP_AND_INT_2ADDR:
1446 case OP_OR_INT_2ADDR:
1447 case OP_XOR_INT_2ADDR:
1448 case OP_SHL_INT_2ADDR:
1449 case OP_SHR_INT_2ADDR:
1450 case OP_USHR_INT_2ADDR:
1451 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1452 break;
1453
1454 case OP_ADD_LONG:
1455 case OP_SUB_LONG:
1456 case OP_MUL_LONG:
1457 case OP_DIV_LONG:
1458 case OP_REM_LONG:
1459 case OP_AND_LONG:
1460 case OP_OR_LONG:
1461 case OP_XOR_LONG:
1462 case OP_ADD_LONG_2ADDR:
1463 case OP_SUB_LONG_2ADDR:
1464 case OP_MUL_LONG_2ADDR:
1465 case OP_DIV_LONG_2ADDR:
1466 case OP_REM_LONG_2ADDR:
1467 case OP_AND_LONG_2ADDR:
1468 case OP_OR_LONG_2ADDR:
1469 case OP_XOR_LONG_2ADDR:
1470 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1471 break;
1472
buzbee67bf8852011-08-17 17:51:35 -07001473 case OP_SHL_LONG:
1474 case OP_SHR_LONG:
1475 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001476 case OP_SHL_LONG_2ADDR:
1477 case OP_SHR_LONG_2ADDR:
1478 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001479 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1480 break;
1481
1482 case OP_ADD_FLOAT:
1483 case OP_SUB_FLOAT:
1484 case OP_MUL_FLOAT:
1485 case OP_DIV_FLOAT:
1486 case OP_REM_FLOAT:
1487 case OP_ADD_FLOAT_2ADDR:
1488 case OP_SUB_FLOAT_2ADDR:
1489 case OP_MUL_FLOAT_2ADDR:
1490 case OP_DIV_FLOAT_2ADDR:
1491 case OP_REM_FLOAT_2ADDR:
1492 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1493 break;
1494
1495 case OP_ADD_DOUBLE:
1496 case OP_SUB_DOUBLE:
1497 case OP_MUL_DOUBLE:
1498 case OP_DIV_DOUBLE:
1499 case OP_REM_DOUBLE:
1500 case OP_ADD_DOUBLE_2ADDR:
1501 case OP_SUB_DOUBLE_2ADDR:
1502 case OP_MUL_DOUBLE_2ADDR:
1503 case OP_DIV_DOUBLE_2ADDR:
1504 case OP_REM_DOUBLE_2ADDR:
1505 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1506 break;
1507
1508 case OP_RSUB_INT:
1509 case OP_ADD_INT_LIT16:
1510 case OP_MUL_INT_LIT16:
1511 case OP_DIV_INT_LIT16:
1512 case OP_REM_INT_LIT16:
1513 case OP_AND_INT_LIT16:
1514 case OP_OR_INT_LIT16:
1515 case OP_XOR_INT_LIT16:
1516 case OP_ADD_INT_LIT8:
1517 case OP_RSUB_INT_LIT8:
1518 case OP_MUL_INT_LIT8:
1519 case OP_DIV_INT_LIT8:
1520 case OP_REM_INT_LIT8:
1521 case OP_AND_INT_LIT8:
1522 case OP_OR_INT_LIT8:
1523 case OP_XOR_INT_LIT8:
1524 case OP_SHL_INT_LIT8:
1525 case OP_SHR_INT_LIT8:
1526 case OP_USHR_INT_LIT8:
1527 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1528 break;
1529
1530 default:
1531 res = true;
1532 }
1533 return res;
1534}
1535
Elliott Hughesc1f143d2011-12-01 17:31:10 -08001536STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001537 "kMirOpPhi",
1538 "kMirOpNullNRangeUpCheck",
1539 "kMirOpNullNRangeDownCheck",
1540 "kMirOpLowerBound",
1541 "kMirOpPunt",
1542 "kMirOpCheckInlinePrediction",
1543};
1544
1545/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001546STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001547{
1548 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
buzbee5abfa3e2012-01-31 17:01:43 -08001549 char* msg = NULL;
1550 if (cUnit->printMe) {
buzbeeba938cb2012-02-03 14:47:55 -08001551 msg = (char*)oatNew(cUnit, strlen(extendedMIROpNames[opOffset]) + 1,
1552 false, kAllocDebugInfo);
buzbee5abfa3e2012-01-31 17:01:43 -08001553 strcpy(msg, extendedMIROpNames[opOffset]);
1554 }
buzbee67bf8852011-08-17 17:51:35 -07001555 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1556
1557 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1558 case kMirOpPhi: {
buzbee5abfa3e2012-01-31 17:01:43 -08001559 char* ssaString = NULL;
1560 if (cUnit->printMe) {
1561 ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1562 }
buzbee67bf8852011-08-17 17:51:35 -07001563 op->flags.isNop = true;
1564 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1565 break;
1566 }
1567 default:
1568 break;
1569 }
1570}
1571
buzbee67bc2362011-10-11 18:08:40 -07001572/*
1573 * If there are any ins passed in registers that have not been promoted
1574 * to a callee-save register, flush them to the frame. Perform intial
1575 * assignment of promoted arguments.
1576 */
buzbeeed3e9302011-09-23 17:34:19 -07001577STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001578{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001579 if (cUnit->numIns == 0)
buzbee67bf8852011-08-17 17:51:35 -07001580 return;
buzbee67bc2362011-10-11 18:08:40 -07001581 int firstArgReg = r1;
1582 int lastArgReg = r3;
Ian Rogersa3760aa2011-11-14 14:32:37 -08001583 int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee8febc582011-10-25 12:39:20 -07001584 /*
1585 * Arguments passed in registers should be flushed
1586 * to their backing locations in the frame for now.
1587 * Also, we need to do initial assignment for promoted
1588 * arguments. NOTE: an older version of dx had an issue
1589 * in which it would reuse static method argument registers.
1590 * This could result in the same Dalvik virtual register
1591 * being promoted to both core and fp regs. In those
1592 * cases, copy argument to both. This will be uncommon
1593 * enough that it isn't worth attempting to optimize.
1594 */
Ian Rogersa3760aa2011-11-14 14:32:37 -08001595 for (int i = 0; i < cUnit->numIns; i++) {
buzbee67bc2362011-10-11 18:08:40 -07001596 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001597 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001598 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001599 if (vMap.coreLocation == kLocPhysReg) {
1600 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001601 }
1602 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001603 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1604 }
1605 // Also put a copy in memory in case we're partially promoted
1606 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1607 firstArgReg + i, kWord);
1608 } else {
buzbee8febc582011-10-25 12:39:20 -07001609 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001610 if (vMap.coreLocation == kLocPhysReg) {
1611 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1612 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001613 }
1614 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001615 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1616 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001617 }
1618 }
buzbee67bf8852011-08-17 17:51:35 -07001619 }
1620}
1621
1622/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001623STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001624{
1625 MIR* mir;
1626 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1627 int blockId = bb->id;
1628
1629 cUnit->curBlock = bb;
1630 labelList[blockId].operands[0] = bb->startOffset;
1631
1632 /* Insert the block label */
1633 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1634 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1635
buzbee6181f792011-09-29 11:14:04 -07001636 /* Reset local optimization data on block boundaries */
1637 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001638 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001639 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001640
1641 ArmLIR* headLIR = NULL;
1642
buzbeebbaf8942011-10-02 13:08:29 -07001643 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001644 if (bb->blockType == kEntryBlock) {
1645 /*
1646 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1647 * mechanism know so it doesn't try to use any of them when
1648 * expanding the frame or flushing. This leaves the utility
1649 * code with a single temp: r12. This should be enough.
1650 */
1651 oatLockTemp(cUnit, r0);
1652 oatLockTemp(cUnit, r1);
1653 oatLockTemp(cUnit, r2);
1654 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001655
1656 /*
1657 * We can safely skip the stack overflow check if we're
1658 * a leaf *and* our frame size < fudge factor.
1659 */
1660 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1661 ((size_t)cUnit->frameSize <
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001662 Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001663 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001664 if (!skipOverflowCheck) {
1665 /* Load stack limit */
1666 loadWordDisp(cUnit, rSELF,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001667 Thread::StackEndOffset().Int32Value(), r12);
buzbeecefd1872011-09-09 09:59:52 -07001668 }
buzbee67bf8852011-08-17 17:51:35 -07001669 /* Spill core callee saves */
1670 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1671 /* Need to spill any FP regs? */
1672 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001673 /*
1674 * NOTE: fp spills are a little different from core spills in that
1675 * they are pushed as a contiguous block. When promoting from
1676 * the fp set, we must allocate all singles from s16..highest-promoted
1677 */
buzbee67bf8852011-08-17 17:51:35 -07001678 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1679 }
buzbeecefd1872011-09-09 09:59:52 -07001680 if (!skipOverflowCheck) {
1681 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001682 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001683 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1684 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001685 genRegCopy(cUnit, rSP, rLR); // Establish stack
1686 } else {
1687 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001688 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001689 }
buzbee67bf8852011-08-17 17:51:35 -07001690 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1691 flushIns(cUnit);
buzbee44b412b2012-02-04 08:50:53 -08001692
1693 if (cUnit->genDebugger) {
1694 // Refresh update debugger callout
1695 loadWordDisp(cUnit, rSELF,
1696 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
1697 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_ENTRY);
1698 }
1699
buzbee67bf8852011-08-17 17:51:35 -07001700 oatFreeTemp(cUnit, r0);
1701 oatFreeTemp(cUnit, r1);
1702 oatFreeTemp(cUnit, r2);
1703 oatFreeTemp(cUnit, r3);
1704 } else if (bb->blockType == kExitBlock) {
1705 newLIR0(cUnit, kArmPseudoMethodExit);
buzbee44b412b2012-02-04 08:50:53 -08001706 /* If we're compiling for the debugger, generate an update callout */
1707 if (cUnit->genDebugger) {
1708 genDebuggerUpdate(cUnit, DEBUGGER_METHOD_EXIT);
1709 }
buzbeebbaf8942011-10-02 13:08:29 -07001710 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07001711 /* Need to restore any FP callee saves? */
1712 if (cUnit->numFPSpills) {
1713 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1714 }
1715 if (cUnit->coreSpillMask & (1 << rLR)) {
1716 /* Unspill rLR to rPC */
1717 cUnit->coreSpillMask &= ~(1 << rLR);
1718 cUnit->coreSpillMask |= (1 << rPC);
1719 }
1720 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1721 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1722 /* We didn't pop to rPC, so must do a bv rLR */
1723 newLIR1(cUnit, kThumbBx, rLR);
1724 }
1725 }
1726
1727 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1728
1729 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07001730 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1731 oatClobberAllRegs(cUnit);
1732 }
buzbee67bf8852011-08-17 17:51:35 -07001733
1734 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1735 oatResetDefTracking(cUnit);
1736 }
1737
1738 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1739 handleExtendedMethodMIR(cUnit, mir);
1740 continue;
1741 }
1742
1743 cUnit->currentDalvikOffset = mir->offset;
1744
1745 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1746 InstructionFormat dalvikFormat =
1747 dexGetFormatFromOpcode(dalvikOpcode);
1748
1749 ArmLIR* boundaryLIR;
1750
1751 /* Mark the beginning of a Dalvik instruction for line tracking */
buzbee5abfa3e2012-01-31 17:01:43 -08001752 char* instStr = cUnit->printMe ?
buzbeeba938cb2012-02-03 14:47:55 -08001753 oatGetDalvikDisassembly(cUnit, &mir->dalvikInsn, "") : NULL;
buzbee67bf8852011-08-17 17:51:35 -07001754 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
buzbee5abfa3e2012-01-31 17:01:43 -08001755 (intptr_t) instStr);
buzbee85d8c1e2012-01-27 15:52:35 -08001756 cUnit->boundaryMap.insert(std::make_pair(mir->offset,
1757 (LIR*)boundaryLIR));
buzbee67bf8852011-08-17 17:51:35 -07001758 /* Remember the first LIR for this block */
1759 if (headLIR == NULL) {
1760 headLIR = boundaryLIR;
1761 /* Set the first boundaryLIR as a scheduling barrier */
1762 headLIR->defMask = ENCODE_ALL;
1763 }
1764
buzbee44b412b2012-02-04 08:50:53 -08001765 /* If we're compiling for the debugger, generate an update callout */
1766 if (cUnit->genDebugger) {
1767 genDebuggerUpdate(cUnit, mir->offset);
1768 }
1769
buzbee67bf8852011-08-17 17:51:35 -07001770 /* Don't generate the SSA annotation unless verbose mode is on */
1771 if (cUnit->printMe && mir->ssaRep) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -08001772 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
buzbee67bf8852011-08-17 17:51:35 -07001773 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1774 }
1775
1776 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1777
1778 if (notHandled) {
1779 char buf[100];
1780 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1781 mir->offset,
1782 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1783 dalvikFormat);
1784 LOG(FATAL) << buf;
1785 }
1786 }
1787
1788 if (headLIR) {
1789 /*
1790 * Eliminate redundant loads/stores and delay stores into later
1791 * slots
1792 */
1793 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1794 cUnit->lastLIRInsn);
1795
1796 /*
1797 * Generate an unconditional branch to the fallthrough block.
1798 */
1799 if (bb->fallThrough) {
1800 genUnconditionalBranch(cUnit,
1801 &labelList[bb->fallThrough->id]);
1802 }
1803 }
1804 return false;
1805}
1806
1807/*
1808 * Nop any unconditional branches that go to the next instruction.
1809 * Note: new redundant branches may be inserted later, and we'll
1810 * use a check in final instruction assembly to nop those out.
1811 */
1812void removeRedundantBranches(CompilationUnit* cUnit)
1813{
1814 ArmLIR* thisLIR;
1815
1816 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1817 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1818 thisLIR = NEXT_LIR(thisLIR)) {
1819
1820 /* Branch to the next instruction */
1821 if ((thisLIR->opcode == kThumbBUncond) ||
1822 (thisLIR->opcode == kThumb2BUncond)) {
1823 ArmLIR* nextLIR = thisLIR;
1824
1825 while (true) {
1826 nextLIR = NEXT_LIR(nextLIR);
1827
1828 /*
1829 * Is the branch target the next instruction?
1830 */
1831 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1832 thisLIR->flags.isNop = true;
1833 break;
1834 }
1835
1836 /*
1837 * Found real useful stuff between the branch and the target.
1838 * Need to explicitly check the lastLIRInsn here because it
1839 * might be the last real instruction.
1840 */
1841 if (!isPseudoOpcode(nextLIR->opcode) ||
1842 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1843 break;
1844 }
1845 }
1846 }
1847}
1848
buzbeeed3e9302011-09-23 17:34:19 -07001849STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07001850{
1851 ArmLIR** suspendLabel =
1852 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
1853 int numElems = cUnit->suspendLaunchpads.numUsed;
1854
1855 for (int i = 0; i < numElems; i++) {
1856 /* TUNING: move suspend count load into helper */
1857 ArmLIR* lab = suspendLabel[i];
1858 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
1859 cUnit->currentDalvikOffset = lab->operands[1];
1860 oatAppendLIR(cUnit, (LIR *)lab);
1861 loadWordDisp(cUnit, rSELF,
1862 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
buzbee44b412b2012-02-04 08:50:53 -08001863 if (!cUnit->genDebugger) {
1864 // use rSUSPEND for suspend count
1865 loadWordDisp(cUnit, rSELF,
1866 Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
1867 }
buzbeec1f45042011-09-21 16:03:19 -07001868 opReg(cUnit, kOpBlx, rLR);
buzbee44b412b2012-02-04 08:50:53 -08001869 if ( cUnit->genDebugger) {
1870 // use rSUSPEND for update debugger
1871 loadWordDisp(cUnit, rSELF,
1872 OFFSETOF_MEMBER(Thread, pUpdateDebuggerFromCode), rSUSPEND);
1873 }
buzbeec1f45042011-09-21 16:03:19 -07001874 genUnconditionalBranch(cUnit, resumeLab);
1875 }
1876}
1877
buzbeeed3e9302011-09-23 17:34:19 -07001878STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07001879{
1880 ArmLIR** throwLabel =
1881 (ArmLIR **) cUnit->throwLaunchpads.elemList;
1882 int numElems = cUnit->throwLaunchpads.numUsed;
1883 int i;
1884
1885 for (i = 0; i < numElems; i++) {
1886 ArmLIR* lab = throwLabel[i];
1887 cUnit->currentDalvikOffset = lab->operands[1];
1888 oatAppendLIR(cUnit, (LIR *)lab);
1889 int funcOffset = 0;
1890 int v1 = lab->operands[2];
1891 int v2 = lab->operands[3];
1892 switch(lab->operands[0]) {
1893 case kArmThrowNullPointer:
1894 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
1895 break;
1896 case kArmThrowArrayBounds:
1897 if (v2 != r0) {
1898 genRegCopy(cUnit, r0, v1);
1899 genRegCopy(cUnit, r1, v2);
1900 } else {
1901 if (v1 == r1) {
1902 genRegCopy(cUnit, r12, v1);
1903 genRegCopy(cUnit, r1, v2);
1904 genRegCopy(cUnit, r0, r12);
1905 } else {
1906 genRegCopy(cUnit, r1, v2);
1907 genRegCopy(cUnit, r0, v1);
1908 }
1909 }
1910 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
1911 break;
1912 case kArmThrowDivZero:
1913 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
1914 break;
1915 case kArmThrowVerificationError:
1916 loadConstant(cUnit, r0, v1);
1917 loadConstant(cUnit, r1, v2);
1918 funcOffset =
1919 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
1920 break;
1921 case kArmThrowNegArraySize:
1922 genRegCopy(cUnit, r0, v1);
1923 funcOffset =
1924 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
1925 break;
buzbee5ade1d22011-09-09 14:44:52 -07001926 case kArmThrowNoSuchMethod:
buzbee13ac45a2012-01-12 12:30:16 -08001927 genRegCopy(cUnit, r0, v1);
buzbee5ade1d22011-09-09 14:44:52 -07001928 funcOffset =
1929 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
1930 break;
buzbeeec5adf32011-09-11 15:25:43 -07001931 case kArmThrowStackOverflow:
1932 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07001933 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07001934 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07001935 opRegImm(cUnit, kOpAdd, rSP,
1936 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07001937 break;
buzbee5ade1d22011-09-09 14:44:52 -07001938 default:
1939 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
1940 }
1941 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07001942 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001943 }
1944}
1945
buzbee67bf8852011-08-17 17:51:35 -07001946void oatMethodMIR2LIR(CompilationUnit* cUnit)
1947{
1948 /* Used to hold the labels of each block */
1949 cUnit->blockLabelList =
buzbeeba938cb2012-02-03 14:47:55 -08001950 (void *) oatNew(cUnit, sizeof(ArmLIR) * cUnit->numBlocks, true,
1951 kAllocLIR);
buzbee67bf8852011-08-17 17:51:35 -07001952
1953 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
1954 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07001955 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07001956
1957 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07001958
1959 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001960}
1961
1962/* Common initialization routine for an architecture family */
1963bool oatArchInit()
1964{
1965 int i;
1966
1967 for (i = 0; i < kArmLast; i++) {
1968 if (EncodingMap[i].opcode != i) {
1969 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
1970 " is wrong: expecting " << i << ", seeing " <<
1971 (int)EncodingMap[i].opcode;
1972 }
1973 }
1974
1975 return oatArchVariantInit();
1976}
1977
1978/* Needed by the Assembler */
1979void oatSetupResourceMasks(ArmLIR* lir)
1980{
1981 setupResourceMasks(lir);
1982}
1983
1984/* Needed by the ld/st optmizatons */
1985ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
1986{
1987 return genRegCopyNoInsert(cUnit, rDest, rSrc);
1988}
1989
1990/* Needed by the register allocator */
1991ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
1992{
1993 return genRegCopy(cUnit, rDest, rSrc);
1994}
1995
1996/* Needed by the register allocator */
1997void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
1998 int srcLo, int srcHi)
1999{
2000 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2001}
2002
2003void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2004 int displacement, int rSrc, OpSize size)
2005{
2006 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2007}
2008
2009void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2010 int displacement, int rSrcLo, int rSrcHi)
2011{
2012 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2013}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002014
2015} // namespace art