blob: 686642342a70e66d745b8fe16da8bd4128bd2b1b [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 Rogersa3760aa2011-11-14 14:32:37 -0800169Field* FindFieldWithResolvedStaticStorage(CompilationUnit* cUnit,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700170 const uint32_t fieldIdx,
171 uint32_t& resolvedTypeIdx) {
Ian Rogersa3760aa2011-11-14 14:32:37 -0800172 Field* field = cUnit->class_linker->ResolveField(*cUnit->dex_file,
173 fieldIdx,
174 cUnit->dex_cache,
175 cUnit->class_loader,
176 true);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700177 if (field == NULL) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700178 Thread* thread = Thread::Current();
179 if (thread->IsExceptionPending()) { // clear any exception left by resolve field
180 thread->ClearException();
181 }
Brian Carlstrom845490b2011-09-19 15:56:53 -0700182 return NULL;
183 }
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800184 const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700185 int type_idx = field_id.class_idx_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800186 Class* klass = cUnit->dex_cache->GetResolvedTypes()->Get(type_idx);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700187 // Check if storage class is the same as class referred to by type idx.
188 // They may not be if the FieldId refers a subclass, but storage is in super
189 if (field->GetDeclaringClass() == klass) {
190 resolvedTypeIdx = type_idx;
191 return field;
192 }
193 // See if we can find a dex reference for the storage class.
194 // we may not if the dex file never references the super class,
195 // but usually it will.
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800196 std::string descriptor(FieldHelper(field).GetDeclaringClassDescriptor());
197 const DexFile::StringId* string_id =
Ian Rogersa3760aa2011-11-14 14:32:37 -0800198 cUnit->dex_file->FindStringId(descriptor);
199 if (string_id == NULL) {
200 return NULL; // descriptor not found, resort to slow path
Brian Carlstrom845490b2011-09-19 15:56:53 -0700201 }
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800202 const DexFile::TypeId* type_id =
Ian Rogersa3760aa2011-11-14 14:32:37 -0800203 cUnit->dex_file->FindTypeId(cUnit->dex_file->GetIndexForStringId(*string_id));
204 if (type_id == NULL) {
205 return NULL; // type id not found, resort to slow path
206 }
207 resolvedTypeIdx = cUnit->dex_file->GetIndexForTypeId(*type_id);
208 return field;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700209}
210
buzbeeed3e9302011-09-23 17:34:19 -0700211STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700212{
buzbeee1931742011-08-28 21:15:53 -0700213 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
214 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700215 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700216 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800217 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700218 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700219 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700220 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700221 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700222 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
223 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700224 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
225 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
226 loadCurrMethodDirect(cUnit, r1);
227 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700228 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700229 } else {
buzbee1da522d2011-09-04 11:22:20 -0700230 // fast path
231 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700232 // Using fixed register to sync with slow path
233 int rMethod = r1;
234 oatLockTemp(cUnit, rMethod);
235 loadCurrMethodDirect(cUnit, rMethod);
236 int rBase = r0;
237 oatLockTemp(cUnit, rBase);
238 loadWordDisp(cUnit, rMethod,
239 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
240 rBase);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800241 loadWordDisp(cUnit, rBase, Array::DataOffset().Int32Value() +
buzbee1da522d2011-09-04 11:22:20 -0700242 sizeof(int32_t*)* typeIdx, rBase);
243 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700244 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700245 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
246 loadWordDisp(cUnit, rSELF,
247 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
248 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700249 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700250 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
251 skipTarget->defMask = ENCODE_ALL;
252 branchOver->generic.target = (LIR*)skipTarget;
253 rlSrc = oatGetSrc(cUnit, mir, 0);
254 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700255#if ANDROID_SMP != 0
256 if (field->IsVolatile()) {
257 oatGenMemBarrier(cUnit, kST);
258 }
259#endif
buzbee1da522d2011-09-04 11:22:20 -0700260 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700261#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700262 if (field->IsVolatile()) {
263 oatGenMemBarrier(cUnit, kSY);
264 }
buzbee67bf8852011-08-17 17:51:35 -0700265#endif
buzbee1da522d2011-09-04 11:22:20 -0700266 if (isObject) {
267 markGCCard(cUnit, rlSrc.lowReg, rBase);
268 }
269 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700270 }
buzbee67bf8852011-08-17 17:51:35 -0700271}
272
buzbeeed3e9302011-09-23 17:34:19 -0700273STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700274{
buzbee1da522d2011-09-04 11:22:20 -0700275 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700276 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800277 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700278 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700279#if ANDROID_SMP != 0
280 bool isVolatile = (field == NULL) || field->IsVolatile();
281#else
282 bool isVolatile = false;
283#endif
284 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700285 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700286 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700287 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
288 loadCurrMethodDirect(cUnit, r1);
289 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700290 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700291 } else {
buzbee1da522d2011-09-04 11:22:20 -0700292 // fast path
293 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700294 // Using fixed register to sync with slow path
295 int rMethod = r1;
296 oatLockTemp(cUnit, rMethod);
297 loadCurrMethodDirect(cUnit, r1);
298 int rBase = r0;
299 oatLockTemp(cUnit, rBase);
300 loadWordDisp(cUnit, rMethod,
301 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
302 rBase);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800303 loadWordDisp(cUnit, rBase, Array::DataOffset().Int32Value() +
buzbee1da522d2011-09-04 11:22:20 -0700304 sizeof(int32_t*)* typeIdx, rBase);
305 // TUNING: fast path should fall through
306 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
307 loadWordDisp(cUnit, rSELF,
308 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
309 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700310 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700311 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
312 skipTarget->defMask = ENCODE_ALL;
313 branchOver->generic.target = (LIR*)skipTarget;
314 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
315 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
316 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
317 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700318 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700319 }
buzbee67bf8852011-08-17 17:51:35 -0700320}
321
322
buzbeeed3e9302011-09-23 17:34:19 -0700323STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700324 RegLocation rlResult, RegLocation rlDest)
325{
buzbee1da522d2011-09-04 11:22:20 -0700326 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700327 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800328 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700329#if ANDROID_SMP != 0
330 bool isVolatile = (field == NULL) || field->IsVolatile();
331#else
332 bool isVolatile = false;
333#endif
buzbee6181f792011-09-29 11:14:04 -0700334 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700335 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700336 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700337 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700338 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
339 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700340 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700341 RegLocation rlResult = oatGetReturnWide(cUnit);
342 storeValueWide(cUnit, rlDest, rlResult);
343 } else {
buzbee1da522d2011-09-04 11:22:20 -0700344 // Fast path
345 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700346 // Using fixed register to sync with slow path
347 int rMethod = r1;
348 oatLockTemp(cUnit, rMethod);
349 loadCurrMethodDirect(cUnit, rMethod);
350 int rBase = r0;
351 oatLockTemp(cUnit, rBase);
352 loadWordDisp(cUnit, rMethod,
353 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
354 rBase);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800355 loadWordDisp(cUnit, rBase, Array::DataOffset().Int32Value() +
buzbee1da522d2011-09-04 11:22:20 -0700356 sizeof(int32_t*)* typeIdx, rBase);
357 // TUNING: fast path should fall through
358 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
359 loadWordDisp(cUnit, rSELF,
360 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
361 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700362 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700363 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
364 skipTarget->defMask = ENCODE_ALL;
365 branchOver->generic.target = (LIR*)skipTarget;
366 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
367 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700368 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
369 rlResult.highReg, INVALID_SREG);
370 oatFreeTemp(cUnit, rBase);
371 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700372 }
buzbee67bf8852011-08-17 17:51:35 -0700373}
374
buzbeeed3e9302011-09-23 17:34:19 -0700375STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700376 RegLocation rlResult, RegLocation rlDest)
377{
buzbee1da522d2011-09-04 11:22:20 -0700378 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700379 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800380 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700381 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
382 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700383 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700384 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700385 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700386 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700387 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
388 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700389 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
390 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
391 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700392 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700393 RegLocation rlResult = oatGetReturn(cUnit);
394 storeValue(cUnit, rlDest, rlResult);
395 } else {
buzbee1da522d2011-09-04 11:22:20 -0700396 // Fast path
397 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700398 // Using fixed register to sync with slow path
399 int rMethod = r1;
400 oatLockTemp(cUnit, rMethod);
401 loadCurrMethodDirect(cUnit, rMethod);
402 int rBase = r0;
403 oatLockTemp(cUnit, rBase);
404 loadWordDisp(cUnit, rMethod,
405 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
406 rBase);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800407 loadWordDisp(cUnit, rBase, Array::DataOffset().Int32Value() +
buzbee1da522d2011-09-04 11:22:20 -0700408 sizeof(int32_t*)* typeIdx, rBase);
409 // TUNING: fast path should fall through
410 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
411 loadWordDisp(cUnit, rSELF,
412 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
413 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700414 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700415 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
416 skipTarget->defMask = ENCODE_ALL;
417 branchOver->generic.target = (LIR*)skipTarget;
418 rlDest = oatGetDest(cUnit, mir, 0);
419 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700420#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700421 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700422 oatGenMemBarrier(cUnit, kSY);
423 }
buzbee67bf8852011-08-17 17:51:35 -0700424#endif
buzbee1da522d2011-09-04 11:22:20 -0700425 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
426 oatFreeTemp(cUnit, rBase);
427 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700428 }
buzbee67bf8852011-08-17 17:51:35 -0700429}
430
buzbee561227c2011-09-02 15:28:19 -0700431typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
432 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700433
434/*
435 * Bit of a hack here - in leiu of a real scheduling pass,
436 * emit the next instruction in static & direct invoke sequences.
437 */
buzbeeed3e9302011-09-23 17:34:19 -0700438STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700439 DecodedInstruction* dInsn, int state,
440 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700441{
buzbee561227c2011-09-02 15:28:19 -0700442 DCHECK(rollback == NULL);
443 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700444 switch(state) {
445 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700446 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700447 break;
buzbee561227c2011-09-02 15:28:19 -0700448 case 1: // Get method->code_and_direct_methods_
449 loadWordDisp(cUnit, r0,
450 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
451 r0);
buzbee67bf8852011-08-17 17:51:35 -0700452 break;
buzbee561227c2011-09-02 15:28:19 -0700453 case 2: // Grab target method* and target code_
454 loadWordDisp(cUnit, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800455 CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
buzbee561227c2011-09-02 15:28:19 -0700456 loadWordDisp(cUnit, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800457 CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700458 break;
459 default:
460 return -1;
461 }
462 return state + 1;
463}
464
buzbee67bf8852011-08-17 17:51:35 -0700465/*
466 * Bit of a hack here - in leiu of a real scheduling pass,
467 * emit the next instruction in a virtual invoke sequence.
468 * We can use rLR as a temp prior to target address loading
469 * Note also that we'll load the first argument ("this") into
470 * r1 here rather than the standard loadArgRegs.
471 */
buzbeeed3e9302011-09-23 17:34:19 -0700472STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700473 DecodedInstruction* dInsn, int state,
474 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700475{
buzbee561227c2011-09-02 15:28:19 -0700476 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700477 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700478 /*
479 * This is the fast path in which the target virtual method is
480 * fully resolved at compile time.
481 */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800482 Method* baseMethod = cUnit->class_linker->ResolveMethod(*cUnit->dex_file,
483 dInsn->vB,
484 cUnit->dex_cache,
485 cUnit->class_loader,
486 false);
buzbee561227c2011-09-02 15:28:19 -0700487 CHECK(baseMethod != NULL);
488 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700489 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700490 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700491 rlArg = oatGetSrc(cUnit, mir, 0);
492 loadValueDirectFixed(cUnit, rlArg, r1);
493 break;
buzbee561227c2011-09-02 15:28:19 -0700494 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700495 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700496 // get this->klass_ [use r1, set rLR]
497 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700498 break;
buzbee561227c2011-09-02 15:28:19 -0700499 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
500 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700501 break;
buzbee561227c2011-09-02 15:28:19 -0700502 case 3: // Get target method [use rLR, set r0]
503 loadWordDisp(cUnit, rLR, (target_idx * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800504 Array::DataOffset().Int32Value(), r0);
buzbee561227c2011-09-02 15:28:19 -0700505 break;
506 case 4: // Get the target compiled code address [uses r0, sets rLR]
507 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700508 break;
509 default:
510 return -1;
511 }
512 return state + 1;
513}
514
buzbeeed3e9302011-09-23 17:34:19 -0700515STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700516 DecodedInstruction* dInsn, int state,
517 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700518{
519 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700520 ArmLIR* skipBranch;
521 ArmLIR* skipTarget;
522 /*
523 * This handles the case in which the base method is not fully
524 * resolved at compile time. We must generate code to test
525 * for resolution a run time, bail to the slow path if not to
526 * fill in all the tables. In the latter case, we'll restart at
527 * at the beginning of the sequence.
528 */
buzbee7b1b86d2011-08-26 18:59:10 -0700529 switch(state) {
530 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700531 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700532 break;
buzbee561227c2011-09-02 15:28:19 -0700533 case 1: // Get method->dex_cache_resolved_methods_
534 loadWordDisp(cUnit, r0,
535 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700536 break;
buzbee561227c2011-09-02 15:28:19 -0700537 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
538 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800539 Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700540 break;
buzbee561227c2011-09-02 15:28:19 -0700541 case 3: // Resolved?
542 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
543 // Slowest path, bail to helper, rollback and retry
544 loadWordDisp(cUnit, rSELF,
545 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
546 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -0800547 loadConstant(cUnit, r2, false);
Ian Rogersff1ed472011-09-20 13:46:24 -0700548 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700549 genUnconditionalBranch(cUnit, rollback);
550 // Resume normal slow path
551 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
552 skipTarget->defMask = ENCODE_ALL;
553 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700554 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700555 loadBaseDisp(cUnit, mir, rLR,
556 Method::GetMethodIndexOffset().Int32Value(), r0,
557 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700558 // Load "this" [set r1]
559 rlArg = oatGetSrc(cUnit, mir, 0);
560 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700561 break;
562 case 4:
563 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700564 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700565 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700566 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700567 break;
buzbee561227c2011-09-02 15:28:19 -0700568 case 5:
569 // get this->klass_->vtable_ [usr rLR, set rLR]
570 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800571 DCHECK_EQ((Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700572 // In load shadow fold vtable_ object header size into method_index_
573 opRegImm(cUnit, kOpAdd, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800574 Array::DataOffset().Int32Value() / 4);
buzbee561227c2011-09-02 15:28:19 -0700575 // Get target Method*
576 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
577 break;
578 case 6: // Get the target compiled code address [uses r0, sets rLR]
579 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700580 break;
581 default:
582 return -1;
583 }
584 return state + 1;
585}
586
buzbeeed3e9302011-09-23 17:34:19 -0700587STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700588 DecodedInstruction* dInsn, int callState,
589 NextCallInsn nextCallInsn, ArmLIR* rollback,
590 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700591{
buzbeec0ecd652011-09-25 18:11:54 -0700592 int nextReg = r1;
593 int nextArg = 0;
594 if (skipThis) {
595 nextReg++;
596 nextArg++;
597 }
598 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
599 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
600 rlArg = oatUpdateRawLoc(cUnit, rlArg);
601 if (rlArg.wide && (nextReg <= r2)) {
602 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
603 nextReg++;
604 nextArg++;
605 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700606 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700607 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700608 }
buzbeec0ecd652011-09-25 18:11:54 -0700609 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700610 }
611 return callState;
612}
613
buzbee4a3164f2011-09-03 11:25:10 -0700614// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700615STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700616 DecodedInstruction* dInsn, int state,
617 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700618{
buzbee510c6052011-10-27 10:47:20 -0700619 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700620 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700621 case 0: // Load trampoline target
622 loadWordDisp(cUnit, rSELF,
623 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
624 rLR);
625 // Load r0 with method index
626 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700627 break;
buzbee67bf8852011-08-17 17:51:35 -0700628 default:
629 return -1;
630 }
631 return state + 1;
632}
633
buzbee67bf8852011-08-17 17:51:35 -0700634/*
635 * Interleave launch code for INVOKE_SUPER. See comments
636 * for nextVCallIns.
637 */
buzbeeed3e9302011-09-23 17:34:19 -0700638STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700639 DecodedInstruction* dInsn, int state,
640 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700641{
buzbee4a3164f2011-09-03 11:25:10 -0700642 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700643 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700644 /*
645 * This is the fast path in which the target virtual method is
646 * fully resolved at compile time. Note also that this path assumes
647 * that the check to verify that the target method index falls
648 * within the size of the super's vtable has been done at compile-time.
649 */
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800650 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -0800651 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
652 dInsn->vB,
653 cUnit->dex_cache,
654 cUnit->class_loader,
655 false);
buzbee4a3164f2011-09-03 11:25:10 -0700656 CHECK(baseMethod != NULL);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800657 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
658 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
659 Class* superClass = (declaring_class != NULL)
660 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -0700661 CHECK(superClass != NULL);
662 int32_t target_idx = baseMethod->GetMethodIndex();
663 CHECK(superClass->GetVTable()->GetLength() > target_idx);
664 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
665 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700666 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700667 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700668 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700669 // Load "this" [set r1]
670 rlArg = oatGetSrc(cUnit, mir, 0);
671 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700672 // Get method->declaring_class_ [use r0, set rLR]
673 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
674 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700675 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700676 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700677 break;
678 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
679 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
680 rLR);
681 break;
682 case 2: // Get ...->super_class_->vtable [u/s rLR]
683 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
684 break;
685 case 3: // Get target method [use rLR, set r0]
686 loadWordDisp(cUnit, rLR, (target_idx * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800687 Array::DataOffset().Int32Value(), r0);
buzbee4a3164f2011-09-03 11:25:10 -0700688 break;
689 case 4: // Get the target compiled code address [uses r0, sets rLR]
690 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
691 break;
buzbee67bf8852011-08-17 17:51:35 -0700692 default:
693 return -1;
694 }
buzbee4a3164f2011-09-03 11:25:10 -0700695 return state + 1;
696}
697
698/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700699STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700700 DecodedInstruction* dInsn, int state,
701 ArmLIR* rollback)
702{
buzbee4a3164f2011-09-03 11:25:10 -0700703 RegLocation rlArg;
704 ArmLIR* skipBranch;
705 ArmLIR* skipTarget;
706 int tReg;
707 /*
708 * This handles the case in which the base method is not fully
709 * resolved at compile time. We must generate code to test
710 * for resolution a run time, bail to the slow path if not to
711 * fill in all the tables. In the latter case, we'll restart at
712 * at the beginning of the sequence.
713 */
714 switch(state) {
715 case 0: // Get the current Method* [sets r0]
716 loadCurrMethodDirect(cUnit, r0);
717 break;
buzbee34c77ad2012-01-11 13:01:32 -0800718 case 1: // Get method->dex_cache_resolved_methods_ [uses r0, set rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700719 loadWordDisp(cUnit, r0,
720 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
721 break;
722 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
723 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800724 Array::DataOffset().Int32Value(), rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700725 break;
726 case 3: // Resolved?
727 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
728 // Slowest path, bail to helper, rollback and retry
729 loadWordDisp(cUnit, rSELF,
730 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
731 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -0800732 loadConstant(cUnit, r2, true);
Ian Rogersff1ed472011-09-20 13:46:24 -0700733 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700734 genUnconditionalBranch(cUnit, rollback);
735 // Resume normal slow path
736 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
737 skipTarget->defMask = ENCODE_ALL;
738 skipBranch->generic.target = (LIR*)skipTarget;
739 // Get base_method->method_index [usr rLR, set rLR]
740 loadBaseDisp(cUnit, mir, rLR,
741 Method::GetMethodIndexOffset().Int32Value(), rLR,
742 kUnsignedHalf, INVALID_SREG);
743 // Load "this" [set r1]
744 rlArg = oatGetSrc(cUnit, mir, 0);
745 loadValueDirectFixed(cUnit, rlArg, r1);
746 // Load curMethod->declaring_class_ [uses r0, sets r0]
747 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
748 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700749 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700750 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700751 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700752 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
753 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700754 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700755 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700756 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700757 // Range check, throw NSM on failure
758 tReg = oatAllocTemp(cUnit);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800759 loadWordDisp(cUnit, r0, Array::LengthOffset().Int32Value(),
buzbee4a3164f2011-09-03 11:25:10 -0700760 tReg);
buzbee13ac45a2012-01-12 12:30:16 -0800761 genRegRegCheck(cUnit, kArmCondCs, rLR, tReg, mir,
buzbeeec5adf32011-09-11 15:25:43 -0700762 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700763 oatFreeTemp(cUnit, tReg);
764 }
buzbee6a0f7f52011-09-05 16:14:20 -0700765 // Adjust vtable_ base past object header
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800766 opRegImm(cUnit, kOpAdd, r0, Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700767 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700768 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700769 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700770 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700771 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
772 break;
773 default:
774 return -1;
775 }
buzbee67bf8852011-08-17 17:51:35 -0700776 return state + 1;
777}
778
779/*
780 * Load up to 5 arguments, the first three of which will be in
781 * r1 .. r3. On entry r0 contains the current method pointer,
782 * and as part of the load sequence, it must be replaced with
783 * the target method pointer. Note, this may also be called
784 * for "range" variants if the number of arguments is 5 or fewer.
785 */
buzbeeed3e9302011-09-23 17:34:19 -0700786STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700787 DecodedInstruction* dInsn, int callState,
788 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700789 NextCallInsn nextCallInsn, ArmLIR* rollback,
790 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700791{
792 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700793
794 /* If no arguments, just return */
795 if (dInsn->vA == 0)
796 return callState;
797
buzbee561227c2011-09-02 15:28:19 -0700798 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700799
buzbeec0ecd652011-09-25 18:11:54 -0700800 DCHECK_LE(dInsn->vA, 5U);
801 if (dInsn->vA > 3) {
802 uint32_t nextUse = 3;
803 //Detect special case of wide arg spanning arg3/arg4
804 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
805 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
806 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
807 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
808 rlUse2.wide) {
809 int reg;
810 // Wide spans, we need the 2nd half of uses[2].
811 rlArg = oatUpdateLocWide(cUnit, rlUse2);
812 if (rlArg.location == kLocPhysReg) {
813 reg = rlArg.highReg;
814 } else {
815 // r2 & r3 can safely be used here
816 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700817 loadWordDisp(cUnit, rSP,
818 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
buzbeec0ecd652011-09-25 18:11:54 -0700819 callState = nextCallInsn(cUnit, mir, dInsn, callState,
820 rollback);
821 }
822 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
823 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
824 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
825 nextUse++;
826 }
827 // Loop through the rest
828 while (nextUse < dInsn->vA) {
829 int lowReg;
830 int highReg;
831 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
832 rlArg = oatUpdateRawLoc(cUnit, rlArg);
833 if (rlArg.location == kLocPhysReg) {
834 lowReg = rlArg.lowReg;
835 highReg = rlArg.highReg;
836 } else {
837 lowReg = r2;
838 highReg = r3;
839 if (rlArg.wide) {
840 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
841 } else {
842 loadValueDirectFixed(cUnit, rlArg, lowReg);
843 }
844 callState = nextCallInsn(cUnit, mir, dInsn, callState,
845 rollback);
846 }
847 int outsOffset = (nextUse + 1) * 4;
848 if (rlArg.wide) {
849 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
850 nextUse += 2;
851 } else {
852 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
853 nextUse++;
854 }
buzbee561227c2011-09-02 15:28:19 -0700855 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700856 }
buzbee67bf8852011-08-17 17:51:35 -0700857 }
858
buzbeec0ecd652011-09-25 18:11:54 -0700859 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
860 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700861
buzbee67bf8852011-08-17 17:51:35 -0700862 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700863 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700864 }
865 return callState;
866}
867
868/*
869 * May have 0+ arguments (also used for jumbo). Note that
870 * source virtual registers may be in physical registers, so may
871 * need to be flushed to home location before copying. This
872 * applies to arg3 and above (see below).
873 *
874 * Two general strategies:
875 * If < 20 arguments
876 * Pass args 3-18 using vldm/vstm block copy
877 * Pass arg0, arg1 & arg2 in r1-r3
878 * If 20+ arguments
879 * Pass args arg19+ using memcpy block copy
880 * Pass arg0, arg1 & arg2 in r1-r3
881 *
882 */
buzbeeed3e9302011-09-23 17:34:19 -0700883STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700884 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700885 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700886 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700887{
888 int firstArg = dInsn->vC;
889 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700890
buzbee67bf8852011-08-17 17:51:35 -0700891 // If we can treat it as non-range (Jumbo ops will use range form)
892 if (numArgs <= 5)
893 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700894 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700895 /*
896 * Make sure range list doesn't span the break between in normal
897 * Dalvik vRegs and the ins.
898 */
buzbee1b4c8592011-08-31 10:43:51 -0700899 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800900 int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee1b4c8592011-08-31 10:43:51 -0700901 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
902 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700903 }
904
905 /*
906 * First load the non-register arguments. Both forms expect all
907 * of the source arguments to be in their home frame location, so
908 * scan the sReg names and flush any that have been promoted to
909 * frame backing storage.
910 */
911 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700912 for (int nextArg = 0; nextArg < numArgs;) {
913 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700914 if (loc.wide) {
915 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700916 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700917 storeBaseDispWide(cUnit, rSP,
918 oatSRegOffset(cUnit, loc.sRegLow),
919 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700920 }
buzbeec0ecd652011-09-25 18:11:54 -0700921 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700922 } else {
923 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700924 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700925 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
926 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700927 }
buzbeec0ecd652011-09-25 18:11:54 -0700928 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700929 }
930 }
931
buzbee67bc2362011-10-11 18:08:40 -0700932 int startOffset = oatSRegOffset(cUnit,
933 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700934 int outsOffset = 4 /* Method* */ + (3 * 4);
935 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700936 // Generate memcpy
937 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
938 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700939 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
940 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700941 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700942 // Restore Method*
943 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700944 } else {
945 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700946 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700947 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700948 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700949 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
950 //TUNING: loosen barrier
951 ld->defMask = ENCODE_ALL;
952 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700953 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700954 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700955 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700956 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
957 setMemRefType(st, false /* isLoad */, kDalvikReg);
958 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700959 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700960 }
961
buzbeec0ecd652011-09-25 18:11:54 -0700962 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
963 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700964
buzbee561227c2011-09-02 15:28:19 -0700965 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee99f27232011-10-05 12:56:36 -0700966 if (pcrLabel) {
967 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
968 }
buzbee67bf8852011-08-17 17:51:35 -0700969 return callState;
970}
971
buzbee2a475e72011-09-07 17:19:17 -0700972// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700973STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700974{
975 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
976 loadWordDisp(cUnit, rSELF,
977 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
978 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
979 target->defMask = -1;
980 branchOver->generic.target = (LIR*)target;
981}
buzbee2a475e72011-09-07 17:19:17 -0700982
buzbeeed3e9302011-09-23 17:34:19 -0700983STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700984 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700985{
986 DecodedInstruction* dInsn = &mir->dalvikInsn;
987 int callState = 0;
988 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700989 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700990 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700991 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700992
buzbee109bd6a2011-09-06 13:58:41 -0700993 // Explicit register usage
994 oatLockCallTemps(cUnit);
995
buzbee99f27232011-10-05 12:56:36 -0700996 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
997 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
998 int idx = mir->dalvikInsn.vB;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800999 Method* target = cUnit->dex_cache->GetResolvedMethods()->Get(idx);
buzbee99f27232011-10-05 12:56:36 -07001000 if (target) {
1001 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
1002 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
1003 loadValueDirectFixed(cUnit, rlArg, r0);
1004 loadWordDisp(cUnit, rSELF,
1005 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
1006 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
1007 opReg(cUnit, kOpBlx, rLR);
1008 oatClobberCalleeSave(cUnit);
1009 return;
1010 }
1011 }
1012 }
1013
buzbee561227c2011-09-02 15:28:19 -07001014 if (range) {
1015 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -07001016 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -07001017 } else {
1018 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -07001019 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -07001020 }
buzbee67bf8852011-08-17 17:51:35 -07001021 // Finish up any of the call sequence not interleaved in arg loading
1022 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001023 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001024 }
buzbeece302932011-10-04 14:32:18 -07001025 if (DISPLAY_MISSING_TARGETS) {
1026 genShowTarget(cUnit);
1027 }
buzbeeec5adf32011-09-11 15:25:43 -07001028 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001029 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001030}
1031
buzbee4a3164f2011-09-03 11:25:10 -07001032/*
1033 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
1034 * which will locate the target and continue on via a tail call.
1035 */
buzbeeed3e9302011-09-23 17:34:19 -07001036STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001037{
1038 DecodedInstruction* dInsn = &mir->dalvikInsn;
1039 int callState = 0;
1040 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -07001041 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001042
1043 // Explicit register usage
1044 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001045 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -07001046 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001047 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
1048 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001049 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -07001050 false);
buzbee67bf8852011-08-17 17:51:35 -07001051 else
1052 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -07001053 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -07001054 // Finish up any of the call sequence not interleaved in arg loading
1055 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001056 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001057 }
buzbeece302932011-10-04 14:32:18 -07001058 if (DISPLAY_MISSING_TARGETS) {
1059 genShowTarget(cUnit);
1060 }
buzbeeec5adf32011-09-11 15:25:43 -07001061 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001062 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001063}
1064
buzbeeed3e9302011-09-23 17:34:19 -07001065STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001066{
1067 DecodedInstruction* dInsn = &mir->dalvikInsn;
1068 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001069 ArmLIR* rollback;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001070 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001071 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
1072 dInsn->vB,
1073 cUnit->dex_cache,
1074 cUnit->class_loader,
1075 false);
buzbee4a3164f2011-09-03 11:25:10 -07001076 NextCallInsn nextCallInsn;
1077 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001078 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001079
1080 // Explicit register usage
1081 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -08001082
1083 // For testing, force call to artResolveMethodFromCode & ignore result
1084 if (EXERCISE_RESOLVE_METHOD) {
1085 loadCurrMethodDirect(cUnit, r0);
1086 loadWordDisp(cUnit, rSELF,
1087 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
1088 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -08001089 loadConstant(cUnit, r2, true);
buzbee34c77ad2012-01-11 13:01:32 -08001090 callRuntimeHelper(cUnit, rLR);
1091 }
1092
buzbee34cd9e52011-09-08 14:31:52 -07001093 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001094 Thread* thread = Thread::Current();
1095 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1096 thread->ClearException();
1097 }
buzbee4a3164f2011-09-03 11:25:10 -07001098 fastPath = false;
1099 } else {
Ian Rogersa3760aa2011-11-14 14:32:37 -08001100 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
1101 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
1102 Class* superClass = (declaring_class != NULL)
1103 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -07001104 if (superClass == NULL) {
1105 fastPath = false;
1106 } else {
1107 int32_t target_idx = baseMethod->GetMethodIndex();
1108 if (superClass->GetVTable()->GetLength() <= target_idx) {
1109 fastPath = false;
1110 } else {
1111 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1112 }
1113 }
1114 }
1115 if (fastPath) {
1116 nextCallInsn = nextSuperCallInsn;
1117 rollback = NULL;
1118 } else {
1119 nextCallInsn = nextSuperCallInsnSP;
1120 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1121 rollback->defMask = -1;
1122 }
buzbee67bf8852011-08-17 17:51:35 -07001123 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001124 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001125 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001126 else
buzbeec0ecd652011-09-25 18:11:54 -07001127 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001128 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001129 // Finish up any of the call sequence not interleaved in arg loading
1130 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001131 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001132 }
buzbeece302932011-10-04 14:32:18 -07001133 if (DISPLAY_MISSING_TARGETS) {
1134 genShowTarget(cUnit);
1135 }
buzbeeec5adf32011-09-11 15:25:43 -07001136 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001137 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001138}
1139
buzbeeed3e9302011-09-23 17:34:19 -07001140STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001141{
1142 DecodedInstruction* dInsn = &mir->dalvikInsn;
1143 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001144 ArmLIR* rollback;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001145 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001146 Method* method = class_linker->ResolveMethod(*cUnit->dex_file,
1147 dInsn->vB,
1148 cUnit->dex_cache,
1149 cUnit->class_loader,
1150 false);
buzbee561227c2011-09-02 15:28:19 -07001151 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001152 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001153 // Explicit register usage
1154 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -08001155
1156 // For testing, force call to artResolveMethodFromCode & ignore result
1157 if (EXERCISE_RESOLVE_METHOD) {
1158 loadCurrMethodDirect(cUnit, r0);
1159 loadWordDisp(cUnit, rSELF,
1160 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
1161 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -08001162 loadConstant(cUnit, r2, false);
buzbee34c77ad2012-01-11 13:01:32 -08001163 callRuntimeHelper(cUnit, rLR);
1164 }
1165
buzbee34cd9e52011-09-08 14:31:52 -07001166 if (SLOW_INVOKE_PATH || method == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001167 Thread* thread = Thread::Current();
1168 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1169 thread->ClearException();
1170 }
buzbee561227c2011-09-02 15:28:19 -07001171 // Slow path
1172 nextCallInsn = nextVCallInsnSP;
1173 // If we need a slow-path callout, we'll restart here
1174 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1175 rollback->defMask = -1;
1176 } else {
1177 // Fast path
1178 nextCallInsn = nextVCallInsn;
1179 rollback = NULL;
1180 }
buzbee67bf8852011-08-17 17:51:35 -07001181 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001182 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001183 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001184 else
buzbeec0ecd652011-09-25 18:11:54 -07001185 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001186 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001187 // Finish up any of the call sequence not interleaved in arg loading
1188 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001189 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001190 }
buzbeece302932011-10-04 14:32:18 -07001191 if (DISPLAY_MISSING_TARGETS) {
1192 genShowTarget(cUnit);
1193 }
buzbeeec5adf32011-09-11 15:25:43 -07001194 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001195 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001196}
1197
buzbeeed3e9302011-09-23 17:34:19 -07001198STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001199 BasicBlock* bb, ArmLIR* labelList)
1200{
1201 bool res = false; // Assume success
1202 RegLocation rlSrc[3];
1203 RegLocation rlDest = badLoc;
1204 RegLocation rlResult = badLoc;
1205 Opcode opcode = mir->dalvikInsn.opcode;
1206
1207 /* Prep Src and Dest locations */
1208 int nextSreg = 0;
1209 int nextLoc = 0;
1210 int attrs = oatDataFlowAttributes[opcode];
1211 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1212 if (attrs & DF_UA) {
1213 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1214 nextSreg++;
1215 } else if (attrs & DF_UA_WIDE) {
1216 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1217 nextSreg + 1);
1218 nextSreg+= 2;
1219 }
1220 if (attrs & DF_UB) {
1221 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1222 nextSreg++;
1223 } else if (attrs & DF_UB_WIDE) {
1224 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1225 nextSreg + 1);
1226 nextSreg+= 2;
1227 }
1228 if (attrs & DF_UC) {
1229 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1230 } else if (attrs & DF_UC_WIDE) {
1231 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1232 nextSreg + 1);
1233 }
1234 if (attrs & DF_DA) {
1235 rlDest = oatGetDest(cUnit, mir, 0);
1236 } else if (attrs & DF_DA_WIDE) {
1237 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1238 }
1239
1240 switch(opcode) {
1241 case OP_NOP:
1242 break;
1243
1244 case OP_MOVE_EXCEPTION:
1245 int exOffset;
1246 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001247 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001248 resetReg = oatAllocTemp(cUnit);
1249 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1250 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1251 loadConstant(cUnit, resetReg, 0);
1252 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1253 storeValue(cUnit, rlDest, rlResult);
1254 break;
1255
1256 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -07001257 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001258 break;
1259
1260 case OP_RETURN:
1261 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -07001262 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001263 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001264 break;
1265
1266 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -07001267 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001268 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001269 break;
1270
1271 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001272 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001273 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001274 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001275 break;
1276
1277 case OP_MOVE_RESULT:
1278 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001279 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001280 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001281 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001282 break;
1283
1284 case OP_MOVE:
1285 case OP_MOVE_OBJECT:
1286 case OP_MOVE_16:
1287 case OP_MOVE_OBJECT_16:
1288 case OP_MOVE_FROM16:
1289 case OP_MOVE_OBJECT_FROM16:
1290 storeValue(cUnit, rlDest, rlSrc[0]);
1291 break;
1292
1293 case OP_MOVE_WIDE:
1294 case OP_MOVE_WIDE_16:
1295 case OP_MOVE_WIDE_FROM16:
1296 storeValueWide(cUnit, rlDest, rlSrc[0]);
1297 break;
1298
1299 case OP_CONST:
1300 case OP_CONST_4:
1301 case OP_CONST_16:
1302 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1303 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1304 storeValue(cUnit, rlDest, rlResult);
1305 break;
1306
1307 case OP_CONST_HIGH16:
1308 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1309 loadConstantNoClobber(cUnit, rlResult.lowReg,
1310 mir->dalvikInsn.vB << 16);
1311 storeValue(cUnit, rlDest, rlResult);
1312 break;
1313
1314 case OP_CONST_WIDE_16:
1315 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001316 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1317 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1318 mir->dalvikInsn.vB,
1319 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001320 storeValueWide(cUnit, rlDest, rlResult);
1321 break;
1322
1323 case OP_CONST_WIDE:
1324 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1325 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001326 mir->dalvikInsn.vB_wide & 0xffffffff,
1327 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001328 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001329 break;
1330
1331 case OP_CONST_WIDE_HIGH16:
1332 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1333 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1334 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001335 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001336 break;
1337
1338 case OP_MONITOR_ENTER:
1339 genMonitorEnter(cUnit, mir, rlSrc[0]);
1340 break;
1341
1342 case OP_MONITOR_EXIT:
1343 genMonitorExit(cUnit, mir, rlSrc[0]);
1344 break;
1345
1346 case OP_CHECK_CAST:
1347 genCheckCast(cUnit, mir, rlSrc[0]);
1348 break;
1349
1350 case OP_INSTANCE_OF:
1351 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1352 break;
1353
1354 case OP_NEW_INSTANCE:
1355 genNewInstance(cUnit, mir, rlDest);
1356 break;
1357
1358 case OP_THROW:
1359 genThrow(cUnit, mir, rlSrc[0]);
1360 break;
1361
buzbee5ade1d22011-09-09 14:44:52 -07001362 case OP_THROW_VERIFICATION_ERROR:
1363 loadWordDisp(cUnit, rSELF,
1364 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1365 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1366 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001367 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001368 break;
1369
buzbee67bf8852011-08-17 17:51:35 -07001370 case OP_ARRAY_LENGTH:
1371 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001372 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001373 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001374 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001375 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1376 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1377 rlResult.lowReg);
1378 storeValue(cUnit, rlDest, rlResult);
1379 break;
1380
1381 case OP_CONST_STRING:
1382 case OP_CONST_STRING_JUMBO:
1383 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1384 break;
1385
1386 case OP_CONST_CLASS:
1387 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1388 break;
1389
1390 case OP_FILL_ARRAY_DATA:
1391 genFillArrayData(cUnit, mir, rlSrc[0]);
1392 break;
1393
1394 case OP_FILLED_NEW_ARRAY:
1395 genFilledNewArray(cUnit, mir, false /* not range */);
1396 break;
1397
1398 case OP_FILLED_NEW_ARRAY_RANGE:
1399 genFilledNewArray(cUnit, mir, true /* range */);
1400 break;
1401
1402 case OP_NEW_ARRAY:
1403 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1404 break;
1405
1406 case OP_GOTO:
1407 case OP_GOTO_16:
1408 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001409 if (bb->taken->startOffset <= mir->offset) {
1410 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001411 }
1412 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1413 break;
1414
1415 case OP_PACKED_SWITCH:
1416 genPackedSwitch(cUnit, mir, rlSrc[0]);
1417 break;
1418
1419 case OP_SPARSE_SWITCH:
1420 genSparseSwitch(cUnit, mir, rlSrc[0]);
1421 break;
1422
1423 case OP_CMPL_FLOAT:
1424 case OP_CMPG_FLOAT:
1425 case OP_CMPL_DOUBLE:
1426 case OP_CMPG_DOUBLE:
1427 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1428 break;
1429
1430 case OP_CMP_LONG:
1431 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1432 break;
1433
1434 case OP_IF_EQ:
1435 case OP_IF_NE:
1436 case OP_IF_LT:
1437 case OP_IF_GE:
1438 case OP_IF_GT:
1439 case OP_IF_LE: {
1440 bool backwardBranch;
1441 ArmConditionCode cond;
1442 backwardBranch = (bb->taken->startOffset <= mir->offset);
1443 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001444 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001445 }
1446 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1447 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1448 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1449 switch(opcode) {
1450 case OP_IF_EQ:
1451 cond = kArmCondEq;
1452 break;
1453 case OP_IF_NE:
1454 cond = kArmCondNe;
1455 break;
1456 case OP_IF_LT:
1457 cond = kArmCondLt;
1458 break;
1459 case OP_IF_GE:
1460 cond = kArmCondGe;
1461 break;
1462 case OP_IF_GT:
1463 cond = kArmCondGt;
1464 break;
1465 case OP_IF_LE:
1466 cond = kArmCondLe;
1467 break;
1468 default:
1469 cond = (ArmConditionCode)0;
1470 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1471 }
1472 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1473 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1474 break;
1475 }
1476
1477 case OP_IF_EQZ:
1478 case OP_IF_NEZ:
1479 case OP_IF_LTZ:
1480 case OP_IF_GEZ:
1481 case OP_IF_GTZ:
1482 case OP_IF_LEZ: {
1483 bool backwardBranch;
1484 ArmConditionCode cond;
1485 backwardBranch = (bb->taken->startOffset <= mir->offset);
1486 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001487 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001488 }
1489 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1490 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1491 switch(opcode) {
1492 case OP_IF_EQZ:
1493 cond = kArmCondEq;
1494 break;
1495 case OP_IF_NEZ:
1496 cond = kArmCondNe;
1497 break;
1498 case OP_IF_LTZ:
1499 cond = kArmCondLt;
1500 break;
1501 case OP_IF_GEZ:
1502 cond = kArmCondGe;
1503 break;
1504 case OP_IF_GTZ:
1505 cond = kArmCondGt;
1506 break;
1507 case OP_IF_LEZ:
1508 cond = kArmCondLe;
1509 break;
1510 default:
1511 cond = (ArmConditionCode)0;
1512 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1513 }
1514 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1515 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1516 break;
1517 }
1518
1519 case OP_AGET_WIDE:
1520 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1521 break;
1522 case OP_AGET:
1523 case OP_AGET_OBJECT:
1524 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1525 break;
1526 case OP_AGET_BOOLEAN:
1527 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1528 rlDest, 0);
1529 break;
1530 case OP_AGET_BYTE:
1531 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1532 break;
1533 case OP_AGET_CHAR:
1534 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1535 rlDest, 1);
1536 break;
1537 case OP_AGET_SHORT:
1538 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1539 break;
1540 case OP_APUT_WIDE:
1541 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1542 break;
1543 case OP_APUT:
1544 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1545 break;
1546 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001547 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001548 break;
1549 case OP_APUT_SHORT:
1550 case OP_APUT_CHAR:
1551 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1552 rlSrc[0], 1);
1553 break;
1554 case OP_APUT_BYTE:
1555 case OP_APUT_BOOLEAN:
1556 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1557 rlSrc[0], 0);
1558 break;
1559
1560 case OP_IGET_WIDE:
1561 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001562 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001563 break;
1564
1565 case OP_IGET:
1566 case OP_IGET_VOLATILE:
1567 case OP_IGET_OBJECT:
1568 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001569 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001570 break;
1571
1572 case OP_IGET_BOOLEAN:
1573 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001574 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001575 break;
1576
1577 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001578 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001579 break;
1580
1581 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001582 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001583 break;
1584
1585 case OP_IPUT_WIDE:
1586 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001587 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001588 break;
1589
1590 case OP_IPUT_OBJECT:
1591 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001592 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001593 break;
1594
1595 case OP_IPUT:
1596 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001597 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001598 break;
1599
1600 case OP_IPUT_BOOLEAN:
1601 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001602 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001603 break;
1604
1605 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001606 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001607 break;
1608
1609 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001610 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001611 break;
1612
1613 case OP_SGET:
1614 case OP_SGET_OBJECT:
1615 case OP_SGET_BOOLEAN:
1616 case OP_SGET_BYTE:
1617 case OP_SGET_CHAR:
1618 case OP_SGET_SHORT:
1619 genSget(cUnit, mir, rlResult, rlDest);
1620 break;
1621
1622 case OP_SGET_WIDE:
1623 genSgetWide(cUnit, mir, rlResult, rlDest);
1624 break;
1625
1626 case OP_SPUT:
1627 case OP_SPUT_OBJECT:
1628 case OP_SPUT_BOOLEAN:
1629 case OP_SPUT_BYTE:
1630 case OP_SPUT_CHAR:
1631 case OP_SPUT_SHORT:
1632 genSput(cUnit, mir, rlSrc[0]);
1633 break;
1634
1635 case OP_SPUT_WIDE:
1636 genSputWide(cUnit, mir, rlSrc[0]);
1637 break;
1638
1639 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001640 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1641 true /*range*/);
1642 break;
buzbee67bf8852011-08-17 17:51:35 -07001643 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001644 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1645 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001646 break;
1647
1648 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001649 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1650 false /*range*/);
1651 break;
buzbee67bf8852011-08-17 17:51:35 -07001652 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001653 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1654 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001655 break;
1656
1657 case OP_INVOKE_VIRTUAL:
1658 case OP_INVOKE_VIRTUAL_RANGE:
1659 genInvokeVirtual(cUnit, mir);
1660 break;
1661
1662 case OP_INVOKE_SUPER:
1663 case OP_INVOKE_SUPER_RANGE:
1664 genInvokeSuper(cUnit, mir);
1665 break;
1666
1667 case OP_INVOKE_INTERFACE:
1668 case OP_INVOKE_INTERFACE_RANGE:
1669 genInvokeInterface(cUnit, mir);
1670 break;
1671
1672 case OP_NEG_INT:
1673 case OP_NOT_INT:
1674 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1675 break;
1676
1677 case OP_NEG_LONG:
1678 case OP_NOT_LONG:
1679 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1680 break;
1681
1682 case OP_NEG_FLOAT:
1683 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1684 break;
1685
1686 case OP_NEG_DOUBLE:
1687 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1688 break;
1689
1690 case OP_INT_TO_LONG:
1691 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1692 if (rlSrc[0].location == kLocPhysReg) {
1693 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1694 } else {
1695 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1696 }
1697 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1698 rlResult.lowReg, 31);
1699 storeValueWide(cUnit, rlDest, rlResult);
1700 break;
1701
1702 case OP_LONG_TO_INT:
1703 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1704 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1705 storeValue(cUnit, rlDest, rlSrc[0]);
1706 break;
1707
1708 case OP_INT_TO_BYTE:
1709 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1710 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1711 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1712 storeValue(cUnit, rlDest, rlResult);
1713 break;
1714
1715 case OP_INT_TO_SHORT:
1716 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1717 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1718 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1719 storeValue(cUnit, rlDest, rlResult);
1720 break;
1721
1722 case OP_INT_TO_CHAR:
1723 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1724 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1725 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1726 storeValue(cUnit, rlDest, rlResult);
1727 break;
1728
1729 case OP_INT_TO_FLOAT:
1730 case OP_INT_TO_DOUBLE:
1731 case OP_LONG_TO_FLOAT:
1732 case OP_LONG_TO_DOUBLE:
1733 case OP_FLOAT_TO_INT:
1734 case OP_FLOAT_TO_LONG:
1735 case OP_FLOAT_TO_DOUBLE:
1736 case OP_DOUBLE_TO_INT:
1737 case OP_DOUBLE_TO_LONG:
1738 case OP_DOUBLE_TO_FLOAT:
1739 genConversion(cUnit, mir);
1740 break;
1741
1742 case OP_ADD_INT:
1743 case OP_SUB_INT:
1744 case OP_MUL_INT:
1745 case OP_DIV_INT:
1746 case OP_REM_INT:
1747 case OP_AND_INT:
1748 case OP_OR_INT:
1749 case OP_XOR_INT:
1750 case OP_SHL_INT:
1751 case OP_SHR_INT:
1752 case OP_USHR_INT:
1753 case OP_ADD_INT_2ADDR:
1754 case OP_SUB_INT_2ADDR:
1755 case OP_MUL_INT_2ADDR:
1756 case OP_DIV_INT_2ADDR:
1757 case OP_REM_INT_2ADDR:
1758 case OP_AND_INT_2ADDR:
1759 case OP_OR_INT_2ADDR:
1760 case OP_XOR_INT_2ADDR:
1761 case OP_SHL_INT_2ADDR:
1762 case OP_SHR_INT_2ADDR:
1763 case OP_USHR_INT_2ADDR:
1764 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1765 break;
1766
1767 case OP_ADD_LONG:
1768 case OP_SUB_LONG:
1769 case OP_MUL_LONG:
1770 case OP_DIV_LONG:
1771 case OP_REM_LONG:
1772 case OP_AND_LONG:
1773 case OP_OR_LONG:
1774 case OP_XOR_LONG:
1775 case OP_ADD_LONG_2ADDR:
1776 case OP_SUB_LONG_2ADDR:
1777 case OP_MUL_LONG_2ADDR:
1778 case OP_DIV_LONG_2ADDR:
1779 case OP_REM_LONG_2ADDR:
1780 case OP_AND_LONG_2ADDR:
1781 case OP_OR_LONG_2ADDR:
1782 case OP_XOR_LONG_2ADDR:
1783 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1784 break;
1785
buzbee67bf8852011-08-17 17:51:35 -07001786 case OP_SHL_LONG:
1787 case OP_SHR_LONG:
1788 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001789 case OP_SHL_LONG_2ADDR:
1790 case OP_SHR_LONG_2ADDR:
1791 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001792 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1793 break;
1794
1795 case OP_ADD_FLOAT:
1796 case OP_SUB_FLOAT:
1797 case OP_MUL_FLOAT:
1798 case OP_DIV_FLOAT:
1799 case OP_REM_FLOAT:
1800 case OP_ADD_FLOAT_2ADDR:
1801 case OP_SUB_FLOAT_2ADDR:
1802 case OP_MUL_FLOAT_2ADDR:
1803 case OP_DIV_FLOAT_2ADDR:
1804 case OP_REM_FLOAT_2ADDR:
1805 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1806 break;
1807
1808 case OP_ADD_DOUBLE:
1809 case OP_SUB_DOUBLE:
1810 case OP_MUL_DOUBLE:
1811 case OP_DIV_DOUBLE:
1812 case OP_REM_DOUBLE:
1813 case OP_ADD_DOUBLE_2ADDR:
1814 case OP_SUB_DOUBLE_2ADDR:
1815 case OP_MUL_DOUBLE_2ADDR:
1816 case OP_DIV_DOUBLE_2ADDR:
1817 case OP_REM_DOUBLE_2ADDR:
1818 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1819 break;
1820
1821 case OP_RSUB_INT:
1822 case OP_ADD_INT_LIT16:
1823 case OP_MUL_INT_LIT16:
1824 case OP_DIV_INT_LIT16:
1825 case OP_REM_INT_LIT16:
1826 case OP_AND_INT_LIT16:
1827 case OP_OR_INT_LIT16:
1828 case OP_XOR_INT_LIT16:
1829 case OP_ADD_INT_LIT8:
1830 case OP_RSUB_INT_LIT8:
1831 case OP_MUL_INT_LIT8:
1832 case OP_DIV_INT_LIT8:
1833 case OP_REM_INT_LIT8:
1834 case OP_AND_INT_LIT8:
1835 case OP_OR_INT_LIT8:
1836 case OP_XOR_INT_LIT8:
1837 case OP_SHL_INT_LIT8:
1838 case OP_SHR_INT_LIT8:
1839 case OP_USHR_INT_LIT8:
1840 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1841 break;
1842
1843 default:
1844 res = true;
1845 }
1846 return res;
1847}
1848
Elliott Hughesc1f143d2011-12-01 17:31:10 -08001849STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001850 "kMirOpPhi",
1851 "kMirOpNullNRangeUpCheck",
1852 "kMirOpNullNRangeDownCheck",
1853 "kMirOpLowerBound",
1854 "kMirOpPunt",
1855 "kMirOpCheckInlinePrediction",
1856};
1857
1858/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001859STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001860{
1861 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
buzbee5abfa3e2012-01-31 17:01:43 -08001862 char* msg = NULL;
1863 if (cUnit->printMe) {
buzbeeba938cb2012-02-03 14:47:55 -08001864 msg = (char*)oatNew(cUnit, strlen(extendedMIROpNames[opOffset]) + 1,
1865 false, kAllocDebugInfo);
buzbee5abfa3e2012-01-31 17:01:43 -08001866 strcpy(msg, extendedMIROpNames[opOffset]);
1867 }
buzbee67bf8852011-08-17 17:51:35 -07001868 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1869
1870 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1871 case kMirOpPhi: {
buzbee5abfa3e2012-01-31 17:01:43 -08001872 char* ssaString = NULL;
1873 if (cUnit->printMe) {
1874 ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1875 }
buzbee67bf8852011-08-17 17:51:35 -07001876 op->flags.isNop = true;
1877 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1878 break;
1879 }
1880 default:
1881 break;
1882 }
1883}
1884
buzbee67bc2362011-10-11 18:08:40 -07001885/*
1886 * If there are any ins passed in registers that have not been promoted
1887 * to a callee-save register, flush them to the frame. Perform intial
1888 * assignment of promoted arguments.
1889 */
buzbeeed3e9302011-09-23 17:34:19 -07001890STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001891{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001892 if (cUnit->numIns == 0)
buzbee67bf8852011-08-17 17:51:35 -07001893 return;
buzbee67bc2362011-10-11 18:08:40 -07001894 int firstArgReg = r1;
1895 int lastArgReg = r3;
Ian Rogersa3760aa2011-11-14 14:32:37 -08001896 int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee8febc582011-10-25 12:39:20 -07001897 /*
1898 * Arguments passed in registers should be flushed
1899 * to their backing locations in the frame for now.
1900 * Also, we need to do initial assignment for promoted
1901 * arguments. NOTE: an older version of dx had an issue
1902 * in which it would reuse static method argument registers.
1903 * This could result in the same Dalvik virtual register
1904 * being promoted to both core and fp regs. In those
1905 * cases, copy argument to both. This will be uncommon
1906 * enough that it isn't worth attempting to optimize.
1907 */
Ian Rogersa3760aa2011-11-14 14:32:37 -08001908 for (int i = 0; i < cUnit->numIns; i++) {
buzbee67bc2362011-10-11 18:08:40 -07001909 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001910 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001911 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001912 if (vMap.coreLocation == kLocPhysReg) {
1913 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001914 }
1915 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001916 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1917 }
1918 // Also put a copy in memory in case we're partially promoted
1919 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1920 firstArgReg + i, kWord);
1921 } else {
buzbee8febc582011-10-25 12:39:20 -07001922 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001923 if (vMap.coreLocation == kLocPhysReg) {
1924 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1925 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001926 }
1927 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001928 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1929 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001930 }
1931 }
buzbee67bf8852011-08-17 17:51:35 -07001932 }
1933}
1934
1935/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001936STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001937{
1938 MIR* mir;
1939 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1940 int blockId = bb->id;
1941
1942 cUnit->curBlock = bb;
1943 labelList[blockId].operands[0] = bb->startOffset;
1944
1945 /* Insert the block label */
1946 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1947 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1948
buzbee6181f792011-09-29 11:14:04 -07001949 /* Reset local optimization data on block boundaries */
1950 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001951 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001952 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001953
1954 ArmLIR* headLIR = NULL;
1955
buzbeebbaf8942011-10-02 13:08:29 -07001956 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001957 if (bb->blockType == kEntryBlock) {
1958 /*
1959 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1960 * mechanism know so it doesn't try to use any of them when
1961 * expanding the frame or flushing. This leaves the utility
1962 * code with a single temp: r12. This should be enough.
1963 */
1964 oatLockTemp(cUnit, r0);
1965 oatLockTemp(cUnit, r1);
1966 oatLockTemp(cUnit, r2);
1967 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001968
1969 /*
1970 * We can safely skip the stack overflow check if we're
1971 * a leaf *and* our frame size < fudge factor.
1972 */
1973 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1974 ((size_t)cUnit->frameSize <
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001975 Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001976 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001977 if (!skipOverflowCheck) {
1978 /* Load stack limit */
1979 loadWordDisp(cUnit, rSELF,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001980 Thread::StackEndOffset().Int32Value(), r12);
buzbeecefd1872011-09-09 09:59:52 -07001981 }
buzbee67bf8852011-08-17 17:51:35 -07001982 /* Spill core callee saves */
1983 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1984 /* Need to spill any FP regs? */
1985 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001986 /*
1987 * NOTE: fp spills are a little different from core spills in that
1988 * they are pushed as a contiguous block. When promoting from
1989 * the fp set, we must allocate all singles from s16..highest-promoted
1990 */
buzbee67bf8852011-08-17 17:51:35 -07001991 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1992 }
buzbeecefd1872011-09-09 09:59:52 -07001993 if (!skipOverflowCheck) {
1994 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001995 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001996 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1997 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001998 genRegCopy(cUnit, rSP, rLR); // Establish stack
1999 } else {
2000 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07002001 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07002002 }
buzbee67bf8852011-08-17 17:51:35 -07002003 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
2004 flushIns(cUnit);
2005 oatFreeTemp(cUnit, r0);
2006 oatFreeTemp(cUnit, r1);
2007 oatFreeTemp(cUnit, r2);
2008 oatFreeTemp(cUnit, r3);
2009 } else if (bb->blockType == kExitBlock) {
2010 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07002011 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07002012 /* Need to restore any FP callee saves? */
2013 if (cUnit->numFPSpills) {
2014 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
2015 }
2016 if (cUnit->coreSpillMask & (1 << rLR)) {
2017 /* Unspill rLR to rPC */
2018 cUnit->coreSpillMask &= ~(1 << rLR);
2019 cUnit->coreSpillMask |= (1 << rPC);
2020 }
2021 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
2022 if (!(cUnit->coreSpillMask & (1 << rPC))) {
2023 /* We didn't pop to rPC, so must do a bv rLR */
2024 newLIR1(cUnit, kThumbBx, rLR);
2025 }
2026 }
2027
2028 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
2029
2030 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07002031 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
2032 oatClobberAllRegs(cUnit);
2033 }
buzbee67bf8852011-08-17 17:51:35 -07002034
2035 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
2036 oatResetDefTracking(cUnit);
2037 }
2038
2039 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
2040 handleExtendedMethodMIR(cUnit, mir);
2041 continue;
2042 }
2043
2044 cUnit->currentDalvikOffset = mir->offset;
2045
2046 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2047 InstructionFormat dalvikFormat =
2048 dexGetFormatFromOpcode(dalvikOpcode);
2049
2050 ArmLIR* boundaryLIR;
2051
2052 /* Mark the beginning of a Dalvik instruction for line tracking */
buzbee5abfa3e2012-01-31 17:01:43 -08002053 char* instStr = cUnit->printMe ?
buzbeeba938cb2012-02-03 14:47:55 -08002054 oatGetDalvikDisassembly(cUnit, &mir->dalvikInsn, "") : NULL;
buzbee67bf8852011-08-17 17:51:35 -07002055 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
buzbee5abfa3e2012-01-31 17:01:43 -08002056 (intptr_t) instStr);
buzbee85d8c1e2012-01-27 15:52:35 -08002057 cUnit->boundaryMap.insert(std::make_pair(mir->offset,
2058 (LIR*)boundaryLIR));
buzbee67bf8852011-08-17 17:51:35 -07002059 /* Remember the first LIR for this block */
2060 if (headLIR == NULL) {
2061 headLIR = boundaryLIR;
2062 /* Set the first boundaryLIR as a scheduling barrier */
2063 headLIR->defMask = ENCODE_ALL;
2064 }
2065
2066 /* Don't generate the SSA annotation unless verbose mode is on */
2067 if (cUnit->printMe && mir->ssaRep) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -08002068 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
buzbee67bf8852011-08-17 17:51:35 -07002069 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
2070 }
2071
2072 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
2073
2074 if (notHandled) {
2075 char buf[100];
2076 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
2077 mir->offset,
2078 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
2079 dalvikFormat);
2080 LOG(FATAL) << buf;
2081 }
2082 }
2083
2084 if (headLIR) {
2085 /*
2086 * Eliminate redundant loads/stores and delay stores into later
2087 * slots
2088 */
2089 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
2090 cUnit->lastLIRInsn);
2091
2092 /*
2093 * Generate an unconditional branch to the fallthrough block.
2094 */
2095 if (bb->fallThrough) {
2096 genUnconditionalBranch(cUnit,
2097 &labelList[bb->fallThrough->id]);
2098 }
2099 }
2100 return false;
2101}
2102
2103/*
2104 * Nop any unconditional branches that go to the next instruction.
2105 * Note: new redundant branches may be inserted later, and we'll
2106 * use a check in final instruction assembly to nop those out.
2107 */
2108void removeRedundantBranches(CompilationUnit* cUnit)
2109{
2110 ArmLIR* thisLIR;
2111
2112 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2113 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2114 thisLIR = NEXT_LIR(thisLIR)) {
2115
2116 /* Branch to the next instruction */
2117 if ((thisLIR->opcode == kThumbBUncond) ||
2118 (thisLIR->opcode == kThumb2BUncond)) {
2119 ArmLIR* nextLIR = thisLIR;
2120
2121 while (true) {
2122 nextLIR = NEXT_LIR(nextLIR);
2123
2124 /*
2125 * Is the branch target the next instruction?
2126 */
2127 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2128 thisLIR->flags.isNop = true;
2129 break;
2130 }
2131
2132 /*
2133 * Found real useful stuff between the branch and the target.
2134 * Need to explicitly check the lastLIRInsn here because it
2135 * might be the last real instruction.
2136 */
2137 if (!isPseudoOpcode(nextLIR->opcode) ||
2138 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2139 break;
2140 }
2141 }
2142 }
2143}
2144
buzbeeed3e9302011-09-23 17:34:19 -07002145STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002146{
2147 ArmLIR** suspendLabel =
2148 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2149 int numElems = cUnit->suspendLaunchpads.numUsed;
2150
2151 for (int i = 0; i < numElems; i++) {
2152 /* TUNING: move suspend count load into helper */
2153 ArmLIR* lab = suspendLabel[i];
2154 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2155 cUnit->currentDalvikOffset = lab->operands[1];
2156 oatAppendLIR(cUnit, (LIR *)lab);
2157 loadWordDisp(cUnit, rSELF,
2158 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2159 loadWordDisp(cUnit, rSELF,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002160 Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
buzbeec1f45042011-09-21 16:03:19 -07002161 opReg(cUnit, kOpBlx, rLR);
2162 genUnconditionalBranch(cUnit, resumeLab);
2163 }
2164}
2165
buzbeeed3e9302011-09-23 17:34:19 -07002166STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002167{
2168 ArmLIR** throwLabel =
2169 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2170 int numElems = cUnit->throwLaunchpads.numUsed;
2171 int i;
2172
2173 for (i = 0; i < numElems; i++) {
2174 ArmLIR* lab = throwLabel[i];
2175 cUnit->currentDalvikOffset = lab->operands[1];
2176 oatAppendLIR(cUnit, (LIR *)lab);
2177 int funcOffset = 0;
2178 int v1 = lab->operands[2];
2179 int v2 = lab->operands[3];
2180 switch(lab->operands[0]) {
2181 case kArmThrowNullPointer:
2182 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2183 break;
2184 case kArmThrowArrayBounds:
2185 if (v2 != r0) {
2186 genRegCopy(cUnit, r0, v1);
2187 genRegCopy(cUnit, r1, v2);
2188 } else {
2189 if (v1 == r1) {
2190 genRegCopy(cUnit, r12, v1);
2191 genRegCopy(cUnit, r1, v2);
2192 genRegCopy(cUnit, r0, r12);
2193 } else {
2194 genRegCopy(cUnit, r1, v2);
2195 genRegCopy(cUnit, r0, v1);
2196 }
2197 }
2198 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2199 break;
2200 case kArmThrowDivZero:
2201 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2202 break;
2203 case kArmThrowVerificationError:
2204 loadConstant(cUnit, r0, v1);
2205 loadConstant(cUnit, r1, v2);
2206 funcOffset =
2207 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2208 break;
2209 case kArmThrowNegArraySize:
2210 genRegCopy(cUnit, r0, v1);
2211 funcOffset =
2212 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2213 break;
buzbee5ade1d22011-09-09 14:44:52 -07002214 case kArmThrowNoSuchMethod:
buzbee13ac45a2012-01-12 12:30:16 -08002215 genRegCopy(cUnit, r0, v1);
buzbee5ade1d22011-09-09 14:44:52 -07002216 funcOffset =
2217 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2218 break;
buzbeeec5adf32011-09-11 15:25:43 -07002219 case kArmThrowStackOverflow:
2220 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002221 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002222 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002223 opRegImm(cUnit, kOpAdd, rSP,
2224 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002225 break;
buzbee5ade1d22011-09-09 14:44:52 -07002226 default:
2227 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2228 }
2229 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002230 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002231 }
2232}
2233
buzbee67bf8852011-08-17 17:51:35 -07002234void oatMethodMIR2LIR(CompilationUnit* cUnit)
2235{
2236 /* Used to hold the labels of each block */
2237 cUnit->blockLabelList =
buzbeeba938cb2012-02-03 14:47:55 -08002238 (void *) oatNew(cUnit, sizeof(ArmLIR) * cUnit->numBlocks, true,
2239 kAllocLIR);
buzbee67bf8852011-08-17 17:51:35 -07002240
2241 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2242 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002243 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002244
2245 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002246
2247 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002248}
2249
2250/* Common initialization routine for an architecture family */
2251bool oatArchInit()
2252{
2253 int i;
2254
2255 for (i = 0; i < kArmLast; i++) {
2256 if (EncodingMap[i].opcode != i) {
2257 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2258 " is wrong: expecting " << i << ", seeing " <<
2259 (int)EncodingMap[i].opcode;
2260 }
2261 }
2262
2263 return oatArchVariantInit();
2264}
2265
2266/* Needed by the Assembler */
2267void oatSetupResourceMasks(ArmLIR* lir)
2268{
2269 setupResourceMasks(lir);
2270}
2271
2272/* Needed by the ld/st optmizatons */
2273ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2274{
2275 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2276}
2277
2278/* Needed by the register allocator */
2279ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2280{
2281 return genRegCopy(cUnit, rDest, rSrc);
2282}
2283
2284/* Needed by the register allocator */
2285void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2286 int srcLo, int srcHi)
2287{
2288 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2289}
2290
2291void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2292 int displacement, int rSrc, OpSize size)
2293{
2294 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2295}
2296
2297void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2298 int displacement, int rSrcLo, int rSrcHi)
2299{
2300 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2301}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002302
2303} // namespace art