blob: 15fd1ba84148a58f06cf45cf9a6d0b50889a9eb1 [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
buzbeece302932011-10-04 14:32:18 -070017#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
18 (1 << kDebugDisplayMissingTargets))
Elliott Hughes1240dad2011-09-09 16:24:50 -070019
buzbee67bc2362011-10-11 18:08:40 -070020STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, INVALID_REG,
21 INVALID_REG, INVALID_SREG};
buzbee6181f792011-09-29 11:14:04 -070022
23/* Mark register usage state and return long retloc */
24STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
25{
26 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
27 oatLockTemp(cUnit, res.lowReg);
28 oatLockTemp(cUnit, res.highReg);
29 oatMarkPair(cUnit, res.lowReg, res.highReg);
30 return res;
31}
32
33STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
34{
35 RegLocation res = LOC_DALVIK_RETURN_VAL;
36 oatLockTemp(cUnit, res.lowReg);
37 return res;
38}
buzbee67bf8852011-08-17 17:51:35 -070039
buzbeedfd3d702011-08-28 12:56:51 -070040/*
41 * Let helper function take care of everything. Will call
42 * Array::AllocFromCode(type_idx, method, count);
43 * Note: AllocFromCode will handle checks for errNegativeArraySize.
44 */
buzbeeed3e9302011-09-23 17:34:19 -070045STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -070046 RegLocation rlSrc)
47{
buzbeedfd3d702011-08-28 12:56:51 -070048 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -070049 uint32_t type_idx = mir->dalvikInsn.vC;
Ian Rogersa3760aa2011-11-14 14:32:37 -080050 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
51 cUnit->dex_cache,
52 *cUnit->dex_file,
53 type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -070054 loadWordDisp(cUnit, rSELF,
55 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
56 } else {
57 UNIMPLEMENTED(WARNING) << "Need to check access of '"
Ian Rogersa3760aa2011-11-14 14:32:37 -080058 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
Ian Rogers28ad40d2011-10-27 15:19:26 -070059 << "' to unresolved type " << type_idx;
60 loadWordDisp(cUnit, rSELF,
61 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
62 }
buzbeedfd3d702011-08-28 12:56:51 -070063 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -070064 loadConstant(cUnit, r0, type_idx); // arg0 <- type_id
buzbeedfd3d702011-08-28 12:56:51 -070065 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070066 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070067 RegLocation rlResult = oatGetReturn(cUnit);
68 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070069}
70
71/*
72 * Similar to genNewArray, but with post-allocation initialization.
73 * Verifier guarantees we're dealing with an array class. Current
74 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
75 * Current code also throws internal unimp if not 'L', '[' or 'I'.
76 */
buzbeeed3e9302011-09-23 17:34:19 -070077STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070078{
79 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070080 int elems = dInsn->vA;
81 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070082 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070083 loadWordDisp(cUnit, rSELF,
Elliott Hughesb408de72011-10-04 14:35:05 -070084 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
Ian Rogersa3760aa2011-11-14 14:32:37 -080085 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
86 cUnit->dex_cache,
87 *cUnit->dex_file,
88 typeId)) {
89 UNIMPLEMENTED(WARNING) << "Need to check access of '"
90 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
91 << "' to unresolved type " << typeId;
Ian Rogers28ad40d2011-10-27 15:19:26 -070092 }
buzbeedfd3d702011-08-28 12:56:51 -070093 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
94 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
95 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070096 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070097 /*
buzbeedfd3d702011-08-28 12:56:51 -070098 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
99 * return region. Because AllocFromCode placed the new array
100 * in r0, we'll just lock it into place. When debugger support is
101 * added, it may be necessary to additionally copy all return
102 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -0700103 */
buzbee67bf8852011-08-17 17:51:35 -0700104 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -0700105
buzbee67bf8852011-08-17 17:51:35 -0700106 // Having a range of 0 is legal
107 if (isRange && (dInsn->vA > 0)) {
108 /*
109 * Bit of ugliness here. We're going generate a mem copy loop
110 * on the register range, but it is possible that some regs
111 * in the range have been promoted. This is unlikely, but
112 * before generating the copy, we'll just force a flush
113 * of any regs in the source range that have been promoted to
114 * home location.
115 */
116 for (unsigned int i = 0; i < dInsn->vA; i++) {
117 RegLocation loc = oatUpdateLoc(cUnit,
118 oatGetSrc(cUnit, mir, i));
119 if (loc.location == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -0700120 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
121 loc.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700122 }
123 }
124 /*
125 * TUNING note: generated code here could be much improved, but
126 * this is an uncommon operation and isn't especially performance
127 * critical.
128 */
129 int rSrc = oatAllocTemp(cUnit);
130 int rDst = oatAllocTemp(cUnit);
131 int rIdx = oatAllocTemp(cUnit);
132 int rVal = rLR; // Using a lot of temps, rLR is known free here
133 // Set up source pointer
134 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
buzbee67bc2362011-10-11 18:08:40 -0700135 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
136 oatSRegOffset(cUnit, rlFirst.sRegLow));
buzbee67bf8852011-08-17 17:51:35 -0700137 // Set up the target pointer
138 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700139 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700140 // Set up the loop counter (known to be > 0)
buzbee31813452011-10-16 14:33:08 -0700141 loadConstant(cUnit, rIdx, dInsn->vA - 1);
buzbee67bf8852011-08-17 17:51:35 -0700142 // Generate the copy loop. Going backwards for convenience
143 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
144 target->defMask = ENCODE_ALL;
145 // Copy next element
146 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
147 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
148 // Use setflags encoding here
149 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee31813452011-10-16 14:33:08 -0700150 ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
buzbee67bf8852011-08-17 17:51:35 -0700151 branch->generic.target = (LIR*)target;
152 } else if (!isRange) {
153 // TUNING: interleave
154 for (unsigned int i = 0; i < dInsn->vA; i++) {
155 RegLocation rlArg = loadValue(cUnit,
156 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700157 storeBaseDisp(cUnit, r0,
158 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700159 i * 4, rlArg.lowReg, kWord);
160 // If the loadValue caused a temp to be allocated, free it
161 if (oatIsTemp(cUnit, rlArg.lowReg)) {
162 oatFreeTemp(cUnit, rlArg.lowReg);
163 }
164 }
165 }
166}
167
Ian Rogersa3760aa2011-11-14 14:32:37 -0800168Field* FindFieldWithResolvedStaticStorage(CompilationUnit* cUnit,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700169 const uint32_t fieldIdx,
170 uint32_t& resolvedTypeIdx) {
Ian Rogersa3760aa2011-11-14 14:32:37 -0800171 Field* field = cUnit->class_linker->ResolveField(*cUnit->dex_file,
172 fieldIdx,
173 cUnit->dex_cache,
174 cUnit->class_loader,
175 true);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700176 if (field == NULL) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700177 Thread* thread = Thread::Current();
178 if (thread->IsExceptionPending()) { // clear any exception left by resolve field
179 thread->ClearException();
180 }
Brian Carlstrom845490b2011-09-19 15:56:53 -0700181 return NULL;
182 }
Ian Rogersa3760aa2011-11-14 14:32:37 -0800183 const art::DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700184 int type_idx = field_id.class_idx_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800185 Class* klass = cUnit->dex_cache->GetResolvedTypes()->Get(type_idx);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700186 // Check if storage class is the same as class referred to by type idx.
187 // They may not be if the FieldId refers a subclass, but storage is in super
188 if (field->GetDeclaringClass() == klass) {
189 resolvedTypeIdx = type_idx;
190 return field;
191 }
192 // See if we can find a dex reference for the storage class.
193 // we may not if the dex file never references the super class,
194 // but usually it will.
195 std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
Ian Rogersa3760aa2011-11-14 14:32:37 -0800196 const art::DexFile::StringId* string_id =
197 cUnit->dex_file->FindStringId(descriptor);
198 if (string_id == NULL) {
199 return NULL; // descriptor not found, resort to slow path
Brian Carlstrom845490b2011-09-19 15:56:53 -0700200 }
Ian Rogersa3760aa2011-11-14 14:32:37 -0800201 const art::DexFile::TypeId* type_id =
202 cUnit->dex_file->FindTypeId(cUnit->dex_file->GetIndexForStringId(*string_id));
203 if (type_id == NULL) {
204 return NULL; // type id not found, resort to slow path
205 }
206 resolvedTypeIdx = cUnit->dex_file->GetIndexForTypeId(*type_id);
207 return field;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700208}
209
buzbeeed3e9302011-09-23 17:34:19 -0700210STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700211{
buzbeee1931742011-08-28 21:15:53 -0700212 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
213 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700214 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700215 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800216 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700217 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700218 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700219 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700220 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700221 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
222 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700223 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
224 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
225 loadCurrMethodDirect(cUnit, r1);
226 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700227 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700228 } else {
buzbee1da522d2011-09-04 11:22:20 -0700229 // fast path
230 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700231 // Using fixed register to sync with slow path
232 int rMethod = r1;
233 oatLockTemp(cUnit, rMethod);
234 loadCurrMethodDirect(cUnit, rMethod);
235 int rBase = r0;
236 oatLockTemp(cUnit, rBase);
237 loadWordDisp(cUnit, rMethod,
238 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
239 rBase);
240 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
241 sizeof(int32_t*)* typeIdx, rBase);
242 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700243 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700244 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
245 loadWordDisp(cUnit, rSELF,
246 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
247 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700248 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700249 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
250 skipTarget->defMask = ENCODE_ALL;
251 branchOver->generic.target = (LIR*)skipTarget;
252 rlSrc = oatGetSrc(cUnit, mir, 0);
253 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700254#if ANDROID_SMP != 0
255 if (field->IsVolatile()) {
256 oatGenMemBarrier(cUnit, kST);
257 }
258#endif
buzbee1da522d2011-09-04 11:22:20 -0700259 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700260#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700261 if (field->IsVolatile()) {
262 oatGenMemBarrier(cUnit, kSY);
263 }
buzbee67bf8852011-08-17 17:51:35 -0700264#endif
buzbee1da522d2011-09-04 11:22:20 -0700265 if (isObject) {
266 markGCCard(cUnit, rlSrc.lowReg, rBase);
267 }
268 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700269 }
buzbee67bf8852011-08-17 17:51:35 -0700270}
271
buzbeeed3e9302011-09-23 17:34:19 -0700272STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700273{
buzbee1da522d2011-09-04 11:22:20 -0700274 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700275 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800276 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700277 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700278#if ANDROID_SMP != 0
279 bool isVolatile = (field == NULL) || field->IsVolatile();
280#else
281 bool isVolatile = false;
282#endif
283 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700284 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700285 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700286 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
287 loadCurrMethodDirect(cUnit, r1);
288 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700289 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700290 } else {
buzbee1da522d2011-09-04 11:22:20 -0700291 // fast path
292 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700293 // Using fixed register to sync with slow path
294 int rMethod = r1;
295 oatLockTemp(cUnit, rMethod);
296 loadCurrMethodDirect(cUnit, r1);
297 int rBase = r0;
298 oatLockTemp(cUnit, rBase);
299 loadWordDisp(cUnit, rMethod,
300 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
301 rBase);
302 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
303 sizeof(int32_t*)* typeIdx, rBase);
304 // TUNING: fast path should fall through
305 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
306 loadWordDisp(cUnit, rSELF,
307 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
308 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700309 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700310 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
311 skipTarget->defMask = ENCODE_ALL;
312 branchOver->generic.target = (LIR*)skipTarget;
313 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
314 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
315 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
316 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700317 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700318 }
buzbee67bf8852011-08-17 17:51:35 -0700319}
320
321
buzbeeed3e9302011-09-23 17:34:19 -0700322STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700323 RegLocation rlResult, RegLocation rlDest)
324{
buzbee1da522d2011-09-04 11:22:20 -0700325 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700326 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800327 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700328#if ANDROID_SMP != 0
329 bool isVolatile = (field == NULL) || field->IsVolatile();
330#else
331 bool isVolatile = false;
332#endif
buzbee6181f792011-09-29 11:14:04 -0700333 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700334 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700335 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700336 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700337 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
338 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700339 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700340 RegLocation rlResult = oatGetReturnWide(cUnit);
341 storeValueWide(cUnit, rlDest, rlResult);
342 } else {
buzbee1da522d2011-09-04 11:22:20 -0700343 // Fast path
344 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700345 // Using fixed register to sync with slow path
346 int rMethod = r1;
347 oatLockTemp(cUnit, rMethod);
348 loadCurrMethodDirect(cUnit, rMethod);
349 int rBase = r0;
350 oatLockTemp(cUnit, rBase);
351 loadWordDisp(cUnit, rMethod,
352 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
353 rBase);
354 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
355 sizeof(int32_t*)* typeIdx, rBase);
356 // TUNING: fast path should fall through
357 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
358 loadWordDisp(cUnit, rSELF,
359 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
360 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700361 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700362 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
363 skipTarget->defMask = ENCODE_ALL;
364 branchOver->generic.target = (LIR*)skipTarget;
365 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
366 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700367 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
368 rlResult.highReg, INVALID_SREG);
369 oatFreeTemp(cUnit, rBase);
370 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700371 }
buzbee67bf8852011-08-17 17:51:35 -0700372}
373
buzbeeed3e9302011-09-23 17:34:19 -0700374STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700375 RegLocation rlResult, RegLocation rlDest)
376{
buzbee1da522d2011-09-04 11:22:20 -0700377 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700378 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800379 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700380 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
381 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700382 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700383 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700384 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700385 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700386 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
387 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700388 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
389 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
390 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700391 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700392 RegLocation rlResult = oatGetReturn(cUnit);
393 storeValue(cUnit, rlDest, rlResult);
394 } else {
buzbee1da522d2011-09-04 11:22:20 -0700395 // Fast path
396 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700397 // Using fixed register to sync with slow path
398 int rMethod = r1;
399 oatLockTemp(cUnit, rMethod);
400 loadCurrMethodDirect(cUnit, rMethod);
401 int rBase = r0;
402 oatLockTemp(cUnit, rBase);
403 loadWordDisp(cUnit, rMethod,
404 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
405 rBase);
406 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
407 sizeof(int32_t*)* typeIdx, rBase);
408 // TUNING: fast path should fall through
409 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
410 loadWordDisp(cUnit, rSELF,
411 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
412 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700413 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700414 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
415 skipTarget->defMask = ENCODE_ALL;
416 branchOver->generic.target = (LIR*)skipTarget;
417 rlDest = oatGetDest(cUnit, mir, 0);
418 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700419#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700420 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700421 oatGenMemBarrier(cUnit, kSY);
422 }
buzbee67bf8852011-08-17 17:51:35 -0700423#endif
buzbee1da522d2011-09-04 11:22:20 -0700424 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
425 oatFreeTemp(cUnit, rBase);
426 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700427 }
buzbee67bf8852011-08-17 17:51:35 -0700428}
429
buzbee561227c2011-09-02 15:28:19 -0700430typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
431 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700432
433/*
434 * Bit of a hack here - in leiu of a real scheduling pass,
435 * emit the next instruction in static & direct invoke sequences.
436 */
buzbeeed3e9302011-09-23 17:34:19 -0700437STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700438 DecodedInstruction* dInsn, int state,
439 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700440{
buzbee561227c2011-09-02 15:28:19 -0700441 DCHECK(rollback == NULL);
442 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700443 switch(state) {
444 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700445 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700446 break;
buzbee561227c2011-09-02 15:28:19 -0700447 case 1: // Get method->code_and_direct_methods_
448 loadWordDisp(cUnit, r0,
449 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
450 r0);
buzbee67bf8852011-08-17 17:51:35 -0700451 break;
buzbee561227c2011-09-02 15:28:19 -0700452 case 2: // Grab target method* and target code_
453 loadWordDisp(cUnit, r0,
454 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
455 loadWordDisp(cUnit, r0,
456 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700457 break;
458 default:
459 return -1;
460 }
461 return state + 1;
462}
463
buzbee67bf8852011-08-17 17:51:35 -0700464/*
465 * Bit of a hack here - in leiu of a real scheduling pass,
466 * emit the next instruction in a virtual invoke sequence.
467 * We can use rLR as a temp prior to target address loading
468 * Note also that we'll load the first argument ("this") into
469 * r1 here rather than the standard loadArgRegs.
470 */
buzbeeed3e9302011-09-23 17:34:19 -0700471STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700472 DecodedInstruction* dInsn, int state,
473 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700474{
buzbee561227c2011-09-02 15:28:19 -0700475 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700476 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700477 /*
478 * This is the fast path in which the target virtual method is
479 * fully resolved at compile time.
480 */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800481 Method* baseMethod = cUnit->class_linker->ResolveMethod(*cUnit->dex_file,
482 dInsn->vB,
483 cUnit->dex_cache,
484 cUnit->class_loader,
485 false);
buzbee561227c2011-09-02 15:28:19 -0700486 CHECK(baseMethod != NULL);
487 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700488 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700489 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700490 rlArg = oatGetSrc(cUnit, mir, 0);
491 loadValueDirectFixed(cUnit, rlArg, r1);
492 break;
buzbee561227c2011-09-02 15:28:19 -0700493 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700494 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700495 // get this->klass_ [use r1, set rLR]
496 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700497 break;
buzbee561227c2011-09-02 15:28:19 -0700498 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
499 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700500 break;
buzbee561227c2011-09-02 15:28:19 -0700501 case 3: // Get target method [use rLR, set r0]
502 loadWordDisp(cUnit, rLR, (target_idx * 4) +
503 art::Array::DataOffset().Int32Value(), r0);
504 break;
505 case 4: // Get the target compiled code address [uses r0, sets rLR]
506 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700507 break;
508 default:
509 return -1;
510 }
511 return state + 1;
512}
513
buzbeeed3e9302011-09-23 17:34:19 -0700514STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700515 DecodedInstruction* dInsn, int state,
516 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700517{
518 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700519 ArmLIR* skipBranch;
520 ArmLIR* skipTarget;
521 /*
522 * This handles the case in which the base method is not fully
523 * resolved at compile time. We must generate code to test
524 * for resolution a run time, bail to the slow path if not to
525 * fill in all the tables. In the latter case, we'll restart at
526 * at the beginning of the sequence.
527 */
buzbee7b1b86d2011-08-26 18:59:10 -0700528 switch(state) {
529 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700530 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700531 break;
buzbee561227c2011-09-02 15:28:19 -0700532 case 1: // Get method->dex_cache_resolved_methods_
533 loadWordDisp(cUnit, r0,
534 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700535 break;
buzbee561227c2011-09-02 15:28:19 -0700536 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
537 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
538 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700539 break;
buzbee561227c2011-09-02 15:28:19 -0700540 case 3: // Resolved?
541 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
542 // Slowest path, bail to helper, rollback and retry
543 loadWordDisp(cUnit, rSELF,
544 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
545 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700546 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700547 genUnconditionalBranch(cUnit, rollback);
548 // Resume normal slow path
549 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
550 skipTarget->defMask = ENCODE_ALL;
551 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700552 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700553 loadBaseDisp(cUnit, mir, rLR,
554 Method::GetMethodIndexOffset().Int32Value(), r0,
555 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700556 // Load "this" [set r1]
557 rlArg = oatGetSrc(cUnit, mir, 0);
558 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700559 break;
560 case 4:
561 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700562 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700563 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700564 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700565 break;
buzbee561227c2011-09-02 15:28:19 -0700566 case 5:
567 // get this->klass_->vtable_ [usr rLR, set rLR]
568 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700569 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700570 // In load shadow fold vtable_ object header size into method_index_
571 opRegImm(cUnit, kOpAdd, r0,
572 art::Array::DataOffset().Int32Value() / 4);
573 // Get target Method*
574 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
575 break;
576 case 6: // Get the target compiled code address [uses r0, sets rLR]
577 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700578 break;
579 default:
580 return -1;
581 }
582 return state + 1;
583}
584
buzbeeed3e9302011-09-23 17:34:19 -0700585STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700586 DecodedInstruction* dInsn, int callState,
587 NextCallInsn nextCallInsn, ArmLIR* rollback,
588 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700589{
buzbeec0ecd652011-09-25 18:11:54 -0700590 int nextReg = r1;
591 int nextArg = 0;
592 if (skipThis) {
593 nextReg++;
594 nextArg++;
595 }
596 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
597 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
598 rlArg = oatUpdateRawLoc(cUnit, rlArg);
599 if (rlArg.wide && (nextReg <= r2)) {
600 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
601 nextReg++;
602 nextArg++;
603 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700604 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700605 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700606 }
buzbeec0ecd652011-09-25 18:11:54 -0700607 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700608 }
609 return callState;
610}
611
buzbee4a3164f2011-09-03 11:25:10 -0700612// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700613STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700614 DecodedInstruction* dInsn, int state,
615 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700616{
buzbee510c6052011-10-27 10:47:20 -0700617 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700618 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700619 case 0: // Load trampoline target
620 loadWordDisp(cUnit, rSELF,
621 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
622 rLR);
623 // Load r0 with method index
624 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700625 break;
buzbee67bf8852011-08-17 17:51:35 -0700626 default:
627 return -1;
628 }
629 return state + 1;
630}
631
buzbee67bf8852011-08-17 17:51:35 -0700632/*
633 * Interleave launch code for INVOKE_SUPER. See comments
634 * for nextVCallIns.
635 */
buzbeeed3e9302011-09-23 17:34:19 -0700636STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700637 DecodedInstruction* dInsn, int state,
638 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700639{
buzbee4a3164f2011-09-03 11:25:10 -0700640 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700641 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700642 /*
643 * This is the fast path in which the target virtual method is
644 * fully resolved at compile time. Note also that this path assumes
645 * that the check to verify that the target method index falls
646 * within the size of the super's vtable has been done at compile-time.
647 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700648 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -0800649 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
650 dInsn->vB,
651 cUnit->dex_cache,
652 cUnit->class_loader,
653 false);
buzbee4a3164f2011-09-03 11:25:10 -0700654 CHECK(baseMethod != NULL);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800655 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
656 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
657 Class* superClass = (declaring_class != NULL)
658 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -0700659 CHECK(superClass != NULL);
660 int32_t target_idx = baseMethod->GetMethodIndex();
661 CHECK(superClass->GetVTable()->GetLength() > target_idx);
662 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
663 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700664 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700665 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700666 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700667 // Load "this" [set r1]
668 rlArg = oatGetSrc(cUnit, mir, 0);
669 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700670 // Get method->declaring_class_ [use r0, set rLR]
671 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
672 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700673 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700674 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700675 break;
676 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
677 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
678 rLR);
679 break;
680 case 2: // Get ...->super_class_->vtable [u/s rLR]
681 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
682 break;
683 case 3: // Get target method [use rLR, set r0]
684 loadWordDisp(cUnit, rLR, (target_idx * 4) +
685 art::Array::DataOffset().Int32Value(), r0);
686 break;
687 case 4: // Get the target compiled code address [uses r0, sets rLR]
688 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
689 break;
buzbee67bf8852011-08-17 17:51:35 -0700690 default:
691 return -1;
692 }
buzbee4a3164f2011-09-03 11:25:10 -0700693 return state + 1;
694}
695
696/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700697STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700698 DecodedInstruction* dInsn, int state,
699 ArmLIR* rollback)
700{
buzbee4a3164f2011-09-03 11:25:10 -0700701 RegLocation rlArg;
702 ArmLIR* skipBranch;
703 ArmLIR* skipTarget;
704 int tReg;
705 /*
706 * This handles the case in which the base method is not fully
707 * resolved at compile time. We must generate code to test
708 * for resolution a run time, bail to the slow path if not to
709 * fill in all the tables. In the latter case, we'll restart at
710 * at the beginning of the sequence.
711 */
712 switch(state) {
713 case 0: // Get the current Method* [sets r0]
714 loadCurrMethodDirect(cUnit, r0);
715 break;
716 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
717 loadWordDisp(cUnit, r0,
718 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
719 break;
720 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
721 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
722 art::Array::DataOffset().Int32Value(), rLR);
723 break;
724 case 3: // Resolved?
725 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
726 // Slowest path, bail to helper, rollback and retry
727 loadWordDisp(cUnit, rSELF,
728 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
729 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700730 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700731 genUnconditionalBranch(cUnit, rollback);
732 // Resume normal slow path
733 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
734 skipTarget->defMask = ENCODE_ALL;
735 skipBranch->generic.target = (LIR*)skipTarget;
736 // Get base_method->method_index [usr rLR, set rLR]
737 loadBaseDisp(cUnit, mir, rLR,
738 Method::GetMethodIndexOffset().Int32Value(), rLR,
739 kUnsignedHalf, INVALID_SREG);
740 // Load "this" [set r1]
741 rlArg = oatGetSrc(cUnit, mir, 0);
742 loadValueDirectFixed(cUnit, rlArg, r1);
743 // Load curMethod->declaring_class_ [uses r0, sets r0]
744 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
745 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700746 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700747 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700748 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700749 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
750 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700751 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700752 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700753 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700754 // Range check, throw NSM on failure
755 tReg = oatAllocTemp(cUnit);
756 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
757 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700758 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
759 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700760 oatFreeTemp(cUnit, tReg);
761 }
buzbee6a0f7f52011-09-05 16:14:20 -0700762 // Adjust vtable_ base past object header
763 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700764 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700765 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700766 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700767 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700768 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
769 break;
770 default:
771 return -1;
772 }
buzbee67bf8852011-08-17 17:51:35 -0700773 return state + 1;
774}
775
776/*
777 * Load up to 5 arguments, the first three of which will be in
778 * r1 .. r3. On entry r0 contains the current method pointer,
779 * and as part of the load sequence, it must be replaced with
780 * the target method pointer. Note, this may also be called
781 * for "range" variants if the number of arguments is 5 or fewer.
782 */
buzbeeed3e9302011-09-23 17:34:19 -0700783STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700784 DecodedInstruction* dInsn, int callState,
785 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700786 NextCallInsn nextCallInsn, ArmLIR* rollback,
787 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700788{
789 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700790
791 /* If no arguments, just return */
792 if (dInsn->vA == 0)
793 return callState;
794
buzbee561227c2011-09-02 15:28:19 -0700795 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700796
buzbeec0ecd652011-09-25 18:11:54 -0700797 DCHECK_LE(dInsn->vA, 5U);
798 if (dInsn->vA > 3) {
799 uint32_t nextUse = 3;
800 //Detect special case of wide arg spanning arg3/arg4
801 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
802 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
803 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
804 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
805 rlUse2.wide) {
806 int reg;
807 // Wide spans, we need the 2nd half of uses[2].
808 rlArg = oatUpdateLocWide(cUnit, rlUse2);
809 if (rlArg.location == kLocPhysReg) {
810 reg = rlArg.highReg;
811 } else {
812 // r2 & r3 can safely be used here
813 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700814 loadWordDisp(cUnit, rSP,
815 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
buzbeec0ecd652011-09-25 18:11:54 -0700816 callState = nextCallInsn(cUnit, mir, dInsn, callState,
817 rollback);
818 }
819 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
820 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
821 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
822 nextUse++;
823 }
824 // Loop through the rest
825 while (nextUse < dInsn->vA) {
826 int lowReg;
827 int highReg;
828 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
829 rlArg = oatUpdateRawLoc(cUnit, rlArg);
830 if (rlArg.location == kLocPhysReg) {
831 lowReg = rlArg.lowReg;
832 highReg = rlArg.highReg;
833 } else {
834 lowReg = r2;
835 highReg = r3;
836 if (rlArg.wide) {
837 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
838 } else {
839 loadValueDirectFixed(cUnit, rlArg, lowReg);
840 }
841 callState = nextCallInsn(cUnit, mir, dInsn, callState,
842 rollback);
843 }
844 int outsOffset = (nextUse + 1) * 4;
845 if (rlArg.wide) {
846 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
847 nextUse += 2;
848 } else {
849 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
850 nextUse++;
851 }
buzbee561227c2011-09-02 15:28:19 -0700852 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700853 }
buzbee67bf8852011-08-17 17:51:35 -0700854 }
855
buzbeec0ecd652011-09-25 18:11:54 -0700856 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
857 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700858
buzbee67bf8852011-08-17 17:51:35 -0700859 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700860 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700861 }
862 return callState;
863}
864
865/*
866 * May have 0+ arguments (also used for jumbo). Note that
867 * source virtual registers may be in physical registers, so may
868 * need to be flushed to home location before copying. This
869 * applies to arg3 and above (see below).
870 *
871 * Two general strategies:
872 * If < 20 arguments
873 * Pass args 3-18 using vldm/vstm block copy
874 * Pass arg0, arg1 & arg2 in r1-r3
875 * If 20+ arguments
876 * Pass args arg19+ using memcpy block copy
877 * Pass arg0, arg1 & arg2 in r1-r3
878 *
879 */
buzbeeed3e9302011-09-23 17:34:19 -0700880STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700881 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700882 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700883 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700884{
885 int firstArg = dInsn->vC;
886 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700887
buzbee67bf8852011-08-17 17:51:35 -0700888 // If we can treat it as non-range (Jumbo ops will use range form)
889 if (numArgs <= 5)
890 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700891 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700892 /*
893 * Make sure range list doesn't span the break between in normal
894 * Dalvik vRegs and the ins.
895 */
buzbee1b4c8592011-08-31 10:43:51 -0700896 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800897 int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee1b4c8592011-08-31 10:43:51 -0700898 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
899 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700900 }
901
902 /*
903 * First load the non-register arguments. Both forms expect all
904 * of the source arguments to be in their home frame location, so
905 * scan the sReg names and flush any that have been promoted to
906 * frame backing storage.
907 */
908 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700909 for (int nextArg = 0; nextArg < numArgs;) {
910 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700911 if (loc.wide) {
912 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700913 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700914 storeBaseDispWide(cUnit, rSP,
915 oatSRegOffset(cUnit, loc.sRegLow),
916 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700917 }
buzbeec0ecd652011-09-25 18:11:54 -0700918 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700919 } else {
920 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700921 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700922 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
923 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700924 }
buzbeec0ecd652011-09-25 18:11:54 -0700925 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700926 }
927 }
928
buzbee67bc2362011-10-11 18:08:40 -0700929 int startOffset = oatSRegOffset(cUnit,
930 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700931 int outsOffset = 4 /* Method* */ + (3 * 4);
932 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700933 // Generate memcpy
934 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
935 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700936 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
937 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700938 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700939 // Restore Method*
940 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700941 } else {
942 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700943 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700944 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700945 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700946 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
947 //TUNING: loosen barrier
948 ld->defMask = ENCODE_ALL;
949 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700950 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700951 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700952 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700953 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
954 setMemRefType(st, false /* isLoad */, kDalvikReg);
955 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700956 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700957 }
958
buzbeec0ecd652011-09-25 18:11:54 -0700959 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
960 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700961
buzbee561227c2011-09-02 15:28:19 -0700962 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee99f27232011-10-05 12:56:36 -0700963 if (pcrLabel) {
964 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
965 }
buzbee67bf8852011-08-17 17:51:35 -0700966 return callState;
967}
968
buzbee2a475e72011-09-07 17:19:17 -0700969// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700970STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700971{
972 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
973 loadWordDisp(cUnit, rSELF,
974 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
975 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
976 target->defMask = -1;
977 branchOver->generic.target = (LIR*)target;
978}
buzbee2a475e72011-09-07 17:19:17 -0700979
buzbeeed3e9302011-09-23 17:34:19 -0700980STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700981 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700982{
983 DecodedInstruction* dInsn = &mir->dalvikInsn;
984 int callState = 0;
985 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700986 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700987 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700988 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700989
buzbee109bd6a2011-09-06 13:58:41 -0700990 // Explicit register usage
991 oatLockCallTemps(cUnit);
992
buzbee99f27232011-10-05 12:56:36 -0700993 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
994 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
995 int idx = mir->dalvikInsn.vB;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800996 Method* target = cUnit->dex_cache->GetResolvedMethods()->Get(idx);
buzbee99f27232011-10-05 12:56:36 -0700997 if (target) {
998 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
999 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
1000 loadValueDirectFixed(cUnit, rlArg, r0);
1001 loadWordDisp(cUnit, rSELF,
1002 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
1003 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
1004 opReg(cUnit, kOpBlx, rLR);
1005 oatClobberCalleeSave(cUnit);
1006 return;
1007 }
1008 }
1009 }
1010
buzbee561227c2011-09-02 15:28:19 -07001011 if (range) {
1012 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -07001013 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -07001014 } else {
1015 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -07001016 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -07001017 }
buzbee67bf8852011-08-17 17:51:35 -07001018 // Finish up any of the call sequence not interleaved in arg loading
1019 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001020 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001021 }
buzbeece302932011-10-04 14:32:18 -07001022 if (DISPLAY_MISSING_TARGETS) {
1023 genShowTarget(cUnit);
1024 }
buzbeeec5adf32011-09-11 15:25:43 -07001025 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001026 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001027}
1028
buzbee4a3164f2011-09-03 11:25:10 -07001029/*
1030 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
1031 * which will locate the target and continue on via a tail call.
1032 */
buzbeeed3e9302011-09-23 17:34:19 -07001033STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001034{
1035 DecodedInstruction* dInsn = &mir->dalvikInsn;
1036 int callState = 0;
1037 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -07001038 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001039
1040 // Explicit register usage
1041 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001042 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -07001043 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001044 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
1045 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001046 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -07001047 false);
buzbee67bf8852011-08-17 17:51:35 -07001048 else
1049 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -07001050 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -07001051 // Finish up any of the call sequence not interleaved in arg loading
1052 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001053 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001054 }
buzbeece302932011-10-04 14:32:18 -07001055 if (DISPLAY_MISSING_TARGETS) {
1056 genShowTarget(cUnit);
1057 }
buzbeeec5adf32011-09-11 15:25:43 -07001058 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001059 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001060}
1061
buzbeeed3e9302011-09-23 17:34:19 -07001062STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001063{
1064 DecodedInstruction* dInsn = &mir->dalvikInsn;
1065 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001066 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001067 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001068 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
1069 dInsn->vB,
1070 cUnit->dex_cache,
1071 cUnit->class_loader,
1072 false);
buzbee4a3164f2011-09-03 11:25:10 -07001073 NextCallInsn nextCallInsn;
1074 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001075 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001076
1077 // Explicit register usage
1078 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001079 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001080 Thread* thread = Thread::Current();
1081 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1082 thread->ClearException();
1083 }
buzbee4a3164f2011-09-03 11:25:10 -07001084 fastPath = false;
1085 } else {
Ian Rogersa3760aa2011-11-14 14:32:37 -08001086 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
1087 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
1088 Class* superClass = (declaring_class != NULL)
1089 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -07001090 if (superClass == NULL) {
1091 fastPath = false;
1092 } else {
1093 int32_t target_idx = baseMethod->GetMethodIndex();
1094 if (superClass->GetVTable()->GetLength() <= target_idx) {
1095 fastPath = false;
1096 } else {
1097 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1098 }
1099 }
1100 }
1101 if (fastPath) {
1102 nextCallInsn = nextSuperCallInsn;
1103 rollback = NULL;
1104 } else {
1105 nextCallInsn = nextSuperCallInsnSP;
1106 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1107 rollback->defMask = -1;
1108 }
buzbee67bf8852011-08-17 17:51:35 -07001109 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001110 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001111 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001112 else
buzbeec0ecd652011-09-25 18:11:54 -07001113 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001114 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001115 // Finish up any of the call sequence not interleaved in arg loading
1116 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001117 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001118 }
buzbeece302932011-10-04 14:32:18 -07001119 if (DISPLAY_MISSING_TARGETS) {
1120 genShowTarget(cUnit);
1121 }
buzbeeec5adf32011-09-11 15:25:43 -07001122 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001123 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001124}
1125
buzbeeed3e9302011-09-23 17:34:19 -07001126STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001127{
1128 DecodedInstruction* dInsn = &mir->dalvikInsn;
1129 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001130 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001131 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001132 Method* method = class_linker->ResolveMethod(*cUnit->dex_file,
1133 dInsn->vB,
1134 cUnit->dex_cache,
1135 cUnit->class_loader,
1136 false);
buzbee561227c2011-09-02 15:28:19 -07001137 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001138 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee7b1b86d2011-08-26 18:59:10 -07001139
buzbee109bd6a2011-09-06 13:58:41 -07001140 // Explicit register usage
1141 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001142 if (SLOW_INVOKE_PATH || method == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001143 Thread* thread = Thread::Current();
1144 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1145 thread->ClearException();
1146 }
buzbee561227c2011-09-02 15:28:19 -07001147 // Slow path
1148 nextCallInsn = nextVCallInsnSP;
1149 // If we need a slow-path callout, we'll restart here
1150 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1151 rollback->defMask = -1;
1152 } else {
1153 // Fast path
1154 nextCallInsn = nextVCallInsn;
1155 rollback = NULL;
1156 }
buzbee67bf8852011-08-17 17:51:35 -07001157 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001158 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001159 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001160 else
buzbeec0ecd652011-09-25 18:11:54 -07001161 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001162 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001163 // Finish up any of the call sequence not interleaved in arg loading
1164 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001165 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001166 }
buzbeece302932011-10-04 14:32:18 -07001167 if (DISPLAY_MISSING_TARGETS) {
1168 genShowTarget(cUnit);
1169 }
buzbeeec5adf32011-09-11 15:25:43 -07001170 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001171 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001172}
1173
buzbeeed3e9302011-09-23 17:34:19 -07001174STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001175 BasicBlock* bb, ArmLIR* labelList)
1176{
1177 bool res = false; // Assume success
1178 RegLocation rlSrc[3];
1179 RegLocation rlDest = badLoc;
1180 RegLocation rlResult = badLoc;
1181 Opcode opcode = mir->dalvikInsn.opcode;
1182
1183 /* Prep Src and Dest locations */
1184 int nextSreg = 0;
1185 int nextLoc = 0;
1186 int attrs = oatDataFlowAttributes[opcode];
1187 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1188 if (attrs & DF_UA) {
1189 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1190 nextSreg++;
1191 } else if (attrs & DF_UA_WIDE) {
1192 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1193 nextSreg + 1);
1194 nextSreg+= 2;
1195 }
1196 if (attrs & DF_UB) {
1197 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1198 nextSreg++;
1199 } else if (attrs & DF_UB_WIDE) {
1200 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1201 nextSreg + 1);
1202 nextSreg+= 2;
1203 }
1204 if (attrs & DF_UC) {
1205 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1206 } else if (attrs & DF_UC_WIDE) {
1207 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1208 nextSreg + 1);
1209 }
1210 if (attrs & DF_DA) {
1211 rlDest = oatGetDest(cUnit, mir, 0);
1212 } else if (attrs & DF_DA_WIDE) {
1213 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1214 }
1215
1216 switch(opcode) {
1217 case OP_NOP:
1218 break;
1219
1220 case OP_MOVE_EXCEPTION:
1221 int exOffset;
1222 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001223 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001224 resetReg = oatAllocTemp(cUnit);
1225 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1226 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1227 loadConstant(cUnit, resetReg, 0);
1228 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1229 storeValue(cUnit, rlDest, rlResult);
1230 break;
1231
1232 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -07001233 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001234 break;
1235
1236 case OP_RETURN:
1237 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -07001238 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001239 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001240 break;
1241
1242 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -07001243 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001244 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001245 break;
1246
1247 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001248 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001249 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001250 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001251 break;
1252
1253 case OP_MOVE_RESULT:
1254 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001255 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001256 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001257 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001258 break;
1259
1260 case OP_MOVE:
1261 case OP_MOVE_OBJECT:
1262 case OP_MOVE_16:
1263 case OP_MOVE_OBJECT_16:
1264 case OP_MOVE_FROM16:
1265 case OP_MOVE_OBJECT_FROM16:
1266 storeValue(cUnit, rlDest, rlSrc[0]);
1267 break;
1268
1269 case OP_MOVE_WIDE:
1270 case OP_MOVE_WIDE_16:
1271 case OP_MOVE_WIDE_FROM16:
1272 storeValueWide(cUnit, rlDest, rlSrc[0]);
1273 break;
1274
1275 case OP_CONST:
1276 case OP_CONST_4:
1277 case OP_CONST_16:
1278 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1279 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1280 storeValue(cUnit, rlDest, rlResult);
1281 break;
1282
1283 case OP_CONST_HIGH16:
1284 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1285 loadConstantNoClobber(cUnit, rlResult.lowReg,
1286 mir->dalvikInsn.vB << 16);
1287 storeValue(cUnit, rlDest, rlResult);
1288 break;
1289
1290 case OP_CONST_WIDE_16:
1291 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001292 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1293 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1294 mir->dalvikInsn.vB,
1295 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001296 storeValueWide(cUnit, rlDest, rlResult);
1297 break;
1298
1299 case OP_CONST_WIDE:
1300 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1301 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001302 mir->dalvikInsn.vB_wide & 0xffffffff,
1303 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001304 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001305 break;
1306
1307 case OP_CONST_WIDE_HIGH16:
1308 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1309 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1310 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001311 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001312 break;
1313
1314 case OP_MONITOR_ENTER:
1315 genMonitorEnter(cUnit, mir, rlSrc[0]);
1316 break;
1317
1318 case OP_MONITOR_EXIT:
1319 genMonitorExit(cUnit, mir, rlSrc[0]);
1320 break;
1321
1322 case OP_CHECK_CAST:
1323 genCheckCast(cUnit, mir, rlSrc[0]);
1324 break;
1325
1326 case OP_INSTANCE_OF:
1327 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1328 break;
1329
1330 case OP_NEW_INSTANCE:
1331 genNewInstance(cUnit, mir, rlDest);
1332 break;
1333
1334 case OP_THROW:
1335 genThrow(cUnit, mir, rlSrc[0]);
1336 break;
1337
buzbee5ade1d22011-09-09 14:44:52 -07001338 case OP_THROW_VERIFICATION_ERROR:
1339 loadWordDisp(cUnit, rSELF,
1340 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1341 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1342 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001343 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001344 break;
1345
buzbee67bf8852011-08-17 17:51:35 -07001346 case OP_ARRAY_LENGTH:
1347 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001348 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001349 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001350 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001351 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1352 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1353 rlResult.lowReg);
1354 storeValue(cUnit, rlDest, rlResult);
1355 break;
1356
1357 case OP_CONST_STRING:
1358 case OP_CONST_STRING_JUMBO:
1359 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1360 break;
1361
1362 case OP_CONST_CLASS:
1363 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1364 break;
1365
1366 case OP_FILL_ARRAY_DATA:
1367 genFillArrayData(cUnit, mir, rlSrc[0]);
1368 break;
1369
1370 case OP_FILLED_NEW_ARRAY:
1371 genFilledNewArray(cUnit, mir, false /* not range */);
1372 break;
1373
1374 case OP_FILLED_NEW_ARRAY_RANGE:
1375 genFilledNewArray(cUnit, mir, true /* range */);
1376 break;
1377
1378 case OP_NEW_ARRAY:
1379 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1380 break;
1381
1382 case OP_GOTO:
1383 case OP_GOTO_16:
1384 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001385 if (bb->taken->startOffset <= mir->offset) {
1386 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001387 }
1388 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1389 break;
1390
1391 case OP_PACKED_SWITCH:
1392 genPackedSwitch(cUnit, mir, rlSrc[0]);
1393 break;
1394
1395 case OP_SPARSE_SWITCH:
1396 genSparseSwitch(cUnit, mir, rlSrc[0]);
1397 break;
1398
1399 case OP_CMPL_FLOAT:
1400 case OP_CMPG_FLOAT:
1401 case OP_CMPL_DOUBLE:
1402 case OP_CMPG_DOUBLE:
1403 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1404 break;
1405
1406 case OP_CMP_LONG:
1407 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1408 break;
1409
1410 case OP_IF_EQ:
1411 case OP_IF_NE:
1412 case OP_IF_LT:
1413 case OP_IF_GE:
1414 case OP_IF_GT:
1415 case OP_IF_LE: {
1416 bool backwardBranch;
1417 ArmConditionCode cond;
1418 backwardBranch = (bb->taken->startOffset <= mir->offset);
1419 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001420 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001421 }
1422 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1423 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1424 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1425 switch(opcode) {
1426 case OP_IF_EQ:
1427 cond = kArmCondEq;
1428 break;
1429 case OP_IF_NE:
1430 cond = kArmCondNe;
1431 break;
1432 case OP_IF_LT:
1433 cond = kArmCondLt;
1434 break;
1435 case OP_IF_GE:
1436 cond = kArmCondGe;
1437 break;
1438 case OP_IF_GT:
1439 cond = kArmCondGt;
1440 break;
1441 case OP_IF_LE:
1442 cond = kArmCondLe;
1443 break;
1444 default:
1445 cond = (ArmConditionCode)0;
1446 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1447 }
1448 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1449 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1450 break;
1451 }
1452
1453 case OP_IF_EQZ:
1454 case OP_IF_NEZ:
1455 case OP_IF_LTZ:
1456 case OP_IF_GEZ:
1457 case OP_IF_GTZ:
1458 case OP_IF_LEZ: {
1459 bool backwardBranch;
1460 ArmConditionCode cond;
1461 backwardBranch = (bb->taken->startOffset <= mir->offset);
1462 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001463 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001464 }
1465 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1466 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1467 switch(opcode) {
1468 case OP_IF_EQZ:
1469 cond = kArmCondEq;
1470 break;
1471 case OP_IF_NEZ:
1472 cond = kArmCondNe;
1473 break;
1474 case OP_IF_LTZ:
1475 cond = kArmCondLt;
1476 break;
1477 case OP_IF_GEZ:
1478 cond = kArmCondGe;
1479 break;
1480 case OP_IF_GTZ:
1481 cond = kArmCondGt;
1482 break;
1483 case OP_IF_LEZ:
1484 cond = kArmCondLe;
1485 break;
1486 default:
1487 cond = (ArmConditionCode)0;
1488 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1489 }
1490 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1491 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1492 break;
1493 }
1494
1495 case OP_AGET_WIDE:
1496 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1497 break;
1498 case OP_AGET:
1499 case OP_AGET_OBJECT:
1500 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1501 break;
1502 case OP_AGET_BOOLEAN:
1503 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1504 rlDest, 0);
1505 break;
1506 case OP_AGET_BYTE:
1507 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1508 break;
1509 case OP_AGET_CHAR:
1510 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1511 rlDest, 1);
1512 break;
1513 case OP_AGET_SHORT:
1514 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1515 break;
1516 case OP_APUT_WIDE:
1517 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1518 break;
1519 case OP_APUT:
1520 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1521 break;
1522 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001523 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001524 break;
1525 case OP_APUT_SHORT:
1526 case OP_APUT_CHAR:
1527 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1528 rlSrc[0], 1);
1529 break;
1530 case OP_APUT_BYTE:
1531 case OP_APUT_BOOLEAN:
1532 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1533 rlSrc[0], 0);
1534 break;
1535
1536 case OP_IGET_WIDE:
1537 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001538 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001539 break;
1540
1541 case OP_IGET:
1542 case OP_IGET_VOLATILE:
1543 case OP_IGET_OBJECT:
1544 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001545 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001546 break;
1547
1548 case OP_IGET_BOOLEAN:
1549 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001550 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001551 break;
1552
1553 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001554 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001555 break;
1556
1557 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001558 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001559 break;
1560
1561 case OP_IPUT_WIDE:
1562 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001563 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001564 break;
1565
1566 case OP_IPUT_OBJECT:
1567 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001568 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001569 break;
1570
1571 case OP_IPUT:
1572 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001573 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001574 break;
1575
1576 case OP_IPUT_BOOLEAN:
1577 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001578 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001579 break;
1580
1581 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001582 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001583 break;
1584
1585 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001586 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001587 break;
1588
1589 case OP_SGET:
1590 case OP_SGET_OBJECT:
1591 case OP_SGET_BOOLEAN:
1592 case OP_SGET_BYTE:
1593 case OP_SGET_CHAR:
1594 case OP_SGET_SHORT:
1595 genSget(cUnit, mir, rlResult, rlDest);
1596 break;
1597
1598 case OP_SGET_WIDE:
1599 genSgetWide(cUnit, mir, rlResult, rlDest);
1600 break;
1601
1602 case OP_SPUT:
1603 case OP_SPUT_OBJECT:
1604 case OP_SPUT_BOOLEAN:
1605 case OP_SPUT_BYTE:
1606 case OP_SPUT_CHAR:
1607 case OP_SPUT_SHORT:
1608 genSput(cUnit, mir, rlSrc[0]);
1609 break;
1610
1611 case OP_SPUT_WIDE:
1612 genSputWide(cUnit, mir, rlSrc[0]);
1613 break;
1614
1615 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001616 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1617 true /*range*/);
1618 break;
buzbee67bf8852011-08-17 17:51:35 -07001619 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001620 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1621 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001622 break;
1623
1624 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001625 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1626 false /*range*/);
1627 break;
buzbee67bf8852011-08-17 17:51:35 -07001628 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001629 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1630 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001631 break;
1632
1633 case OP_INVOKE_VIRTUAL:
1634 case OP_INVOKE_VIRTUAL_RANGE:
1635 genInvokeVirtual(cUnit, mir);
1636 break;
1637
1638 case OP_INVOKE_SUPER:
1639 case OP_INVOKE_SUPER_RANGE:
1640 genInvokeSuper(cUnit, mir);
1641 break;
1642
1643 case OP_INVOKE_INTERFACE:
1644 case OP_INVOKE_INTERFACE_RANGE:
1645 genInvokeInterface(cUnit, mir);
1646 break;
1647
1648 case OP_NEG_INT:
1649 case OP_NOT_INT:
1650 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1651 break;
1652
1653 case OP_NEG_LONG:
1654 case OP_NOT_LONG:
1655 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1656 break;
1657
1658 case OP_NEG_FLOAT:
1659 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1660 break;
1661
1662 case OP_NEG_DOUBLE:
1663 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1664 break;
1665
1666 case OP_INT_TO_LONG:
1667 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1668 if (rlSrc[0].location == kLocPhysReg) {
1669 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1670 } else {
1671 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1672 }
1673 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1674 rlResult.lowReg, 31);
1675 storeValueWide(cUnit, rlDest, rlResult);
1676 break;
1677
1678 case OP_LONG_TO_INT:
1679 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1680 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1681 storeValue(cUnit, rlDest, rlSrc[0]);
1682 break;
1683
1684 case OP_INT_TO_BYTE:
1685 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1686 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1687 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1688 storeValue(cUnit, rlDest, rlResult);
1689 break;
1690
1691 case OP_INT_TO_SHORT:
1692 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1693 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1694 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1695 storeValue(cUnit, rlDest, rlResult);
1696 break;
1697
1698 case OP_INT_TO_CHAR:
1699 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1700 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1701 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1702 storeValue(cUnit, rlDest, rlResult);
1703 break;
1704
1705 case OP_INT_TO_FLOAT:
1706 case OP_INT_TO_DOUBLE:
1707 case OP_LONG_TO_FLOAT:
1708 case OP_LONG_TO_DOUBLE:
1709 case OP_FLOAT_TO_INT:
1710 case OP_FLOAT_TO_LONG:
1711 case OP_FLOAT_TO_DOUBLE:
1712 case OP_DOUBLE_TO_INT:
1713 case OP_DOUBLE_TO_LONG:
1714 case OP_DOUBLE_TO_FLOAT:
1715 genConversion(cUnit, mir);
1716 break;
1717
1718 case OP_ADD_INT:
1719 case OP_SUB_INT:
1720 case OP_MUL_INT:
1721 case OP_DIV_INT:
1722 case OP_REM_INT:
1723 case OP_AND_INT:
1724 case OP_OR_INT:
1725 case OP_XOR_INT:
1726 case OP_SHL_INT:
1727 case OP_SHR_INT:
1728 case OP_USHR_INT:
1729 case OP_ADD_INT_2ADDR:
1730 case OP_SUB_INT_2ADDR:
1731 case OP_MUL_INT_2ADDR:
1732 case OP_DIV_INT_2ADDR:
1733 case OP_REM_INT_2ADDR:
1734 case OP_AND_INT_2ADDR:
1735 case OP_OR_INT_2ADDR:
1736 case OP_XOR_INT_2ADDR:
1737 case OP_SHL_INT_2ADDR:
1738 case OP_SHR_INT_2ADDR:
1739 case OP_USHR_INT_2ADDR:
1740 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1741 break;
1742
1743 case OP_ADD_LONG:
1744 case OP_SUB_LONG:
1745 case OP_MUL_LONG:
1746 case OP_DIV_LONG:
1747 case OP_REM_LONG:
1748 case OP_AND_LONG:
1749 case OP_OR_LONG:
1750 case OP_XOR_LONG:
1751 case OP_ADD_LONG_2ADDR:
1752 case OP_SUB_LONG_2ADDR:
1753 case OP_MUL_LONG_2ADDR:
1754 case OP_DIV_LONG_2ADDR:
1755 case OP_REM_LONG_2ADDR:
1756 case OP_AND_LONG_2ADDR:
1757 case OP_OR_LONG_2ADDR:
1758 case OP_XOR_LONG_2ADDR:
1759 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1760 break;
1761
buzbee67bf8852011-08-17 17:51:35 -07001762 case OP_SHL_LONG:
1763 case OP_SHR_LONG:
1764 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001765 case OP_SHL_LONG_2ADDR:
1766 case OP_SHR_LONG_2ADDR:
1767 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001768 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1769 break;
1770
1771 case OP_ADD_FLOAT:
1772 case OP_SUB_FLOAT:
1773 case OP_MUL_FLOAT:
1774 case OP_DIV_FLOAT:
1775 case OP_REM_FLOAT:
1776 case OP_ADD_FLOAT_2ADDR:
1777 case OP_SUB_FLOAT_2ADDR:
1778 case OP_MUL_FLOAT_2ADDR:
1779 case OP_DIV_FLOAT_2ADDR:
1780 case OP_REM_FLOAT_2ADDR:
1781 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1782 break;
1783
1784 case OP_ADD_DOUBLE:
1785 case OP_SUB_DOUBLE:
1786 case OP_MUL_DOUBLE:
1787 case OP_DIV_DOUBLE:
1788 case OP_REM_DOUBLE:
1789 case OP_ADD_DOUBLE_2ADDR:
1790 case OP_SUB_DOUBLE_2ADDR:
1791 case OP_MUL_DOUBLE_2ADDR:
1792 case OP_DIV_DOUBLE_2ADDR:
1793 case OP_REM_DOUBLE_2ADDR:
1794 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1795 break;
1796
1797 case OP_RSUB_INT:
1798 case OP_ADD_INT_LIT16:
1799 case OP_MUL_INT_LIT16:
1800 case OP_DIV_INT_LIT16:
1801 case OP_REM_INT_LIT16:
1802 case OP_AND_INT_LIT16:
1803 case OP_OR_INT_LIT16:
1804 case OP_XOR_INT_LIT16:
1805 case OP_ADD_INT_LIT8:
1806 case OP_RSUB_INT_LIT8:
1807 case OP_MUL_INT_LIT8:
1808 case OP_DIV_INT_LIT8:
1809 case OP_REM_INT_LIT8:
1810 case OP_AND_INT_LIT8:
1811 case OP_OR_INT_LIT8:
1812 case OP_XOR_INT_LIT8:
1813 case OP_SHL_INT_LIT8:
1814 case OP_SHR_INT_LIT8:
1815 case OP_USHR_INT_LIT8:
1816 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1817 break;
1818
1819 default:
1820 res = true;
1821 }
1822 return res;
1823}
1824
Elliott Hughesc1f143d2011-12-01 17:31:10 -08001825STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001826 "kMirOpPhi",
1827 "kMirOpNullNRangeUpCheck",
1828 "kMirOpNullNRangeDownCheck",
1829 "kMirOpLowerBound",
1830 "kMirOpPunt",
1831 "kMirOpCheckInlinePrediction",
1832};
1833
1834/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001835STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001836{
1837 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1838 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1839 strcpy(msg, extendedMIROpNames[opOffset]);
1840 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1841
1842 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1843 case kMirOpPhi: {
1844 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1845 op->flags.isNop = true;
1846 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1847 break;
1848 }
1849 default:
1850 break;
1851 }
1852}
1853
buzbee67bc2362011-10-11 18:08:40 -07001854/*
1855 * If there are any ins passed in registers that have not been promoted
1856 * to a callee-save register, flush them to the frame. Perform intial
1857 * assignment of promoted arguments.
1858 */
buzbeeed3e9302011-09-23 17:34:19 -07001859STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001860{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001861 if (cUnit->numIns == 0)
buzbee67bf8852011-08-17 17:51:35 -07001862 return;
buzbee67bc2362011-10-11 18:08:40 -07001863 int firstArgReg = r1;
1864 int lastArgReg = r3;
Ian Rogersa3760aa2011-11-14 14:32:37 -08001865 int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee8febc582011-10-25 12:39:20 -07001866 /*
1867 * Arguments passed in registers should be flushed
1868 * to their backing locations in the frame for now.
1869 * Also, we need to do initial assignment for promoted
1870 * arguments. NOTE: an older version of dx had an issue
1871 * in which it would reuse static method argument registers.
1872 * This could result in the same Dalvik virtual register
1873 * being promoted to both core and fp regs. In those
1874 * cases, copy argument to both. This will be uncommon
1875 * enough that it isn't worth attempting to optimize.
1876 */
Ian Rogersa3760aa2011-11-14 14:32:37 -08001877 for (int i = 0; i < cUnit->numIns; i++) {
buzbee67bc2362011-10-11 18:08:40 -07001878 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001879 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001880 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001881 if (vMap.coreLocation == kLocPhysReg) {
1882 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001883 }
1884 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001885 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1886 }
1887 // Also put a copy in memory in case we're partially promoted
1888 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1889 firstArgReg + i, kWord);
1890 } else {
buzbee8febc582011-10-25 12:39:20 -07001891 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001892 if (vMap.coreLocation == kLocPhysReg) {
1893 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1894 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001895 }
1896 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001897 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1898 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001899 }
1900 }
buzbee67bf8852011-08-17 17:51:35 -07001901 }
1902}
1903
1904/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001905STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001906{
1907 MIR* mir;
1908 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1909 int blockId = bb->id;
1910
1911 cUnit->curBlock = bb;
1912 labelList[blockId].operands[0] = bb->startOffset;
1913
1914 /* Insert the block label */
1915 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1916 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1917
buzbee6181f792011-09-29 11:14:04 -07001918 /* Reset local optimization data on block boundaries */
1919 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001920 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001921 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001922
1923 ArmLIR* headLIR = NULL;
1924
buzbeebbaf8942011-10-02 13:08:29 -07001925 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001926 if (bb->blockType == kEntryBlock) {
1927 /*
1928 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1929 * mechanism know so it doesn't try to use any of them when
1930 * expanding the frame or flushing. This leaves the utility
1931 * code with a single temp: r12. This should be enough.
1932 */
1933 oatLockTemp(cUnit, r0);
1934 oatLockTemp(cUnit, r1);
1935 oatLockTemp(cUnit, r2);
1936 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001937
1938 /*
1939 * We can safely skip the stack overflow check if we're
1940 * a leaf *and* our frame size < fudge factor.
1941 */
1942 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1943 ((size_t)cUnit->frameSize <
1944 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001945 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001946 if (!skipOverflowCheck) {
1947 /* Load stack limit */
1948 loadWordDisp(cUnit, rSELF,
1949 art::Thread::StackEndOffset().Int32Value(), r12);
1950 }
buzbee67bf8852011-08-17 17:51:35 -07001951 /* Spill core callee saves */
1952 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1953 /* Need to spill any FP regs? */
1954 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001955 /*
1956 * NOTE: fp spills are a little different from core spills in that
1957 * they are pushed as a contiguous block. When promoting from
1958 * the fp set, we must allocate all singles from s16..highest-promoted
1959 */
buzbee67bf8852011-08-17 17:51:35 -07001960 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1961 }
buzbeecefd1872011-09-09 09:59:52 -07001962 if (!skipOverflowCheck) {
1963 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001964 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001965 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1966 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001967 genRegCopy(cUnit, rSP, rLR); // Establish stack
1968 } else {
1969 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001970 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001971 }
buzbee67bf8852011-08-17 17:51:35 -07001972 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1973 flushIns(cUnit);
1974 oatFreeTemp(cUnit, r0);
1975 oatFreeTemp(cUnit, r1);
1976 oatFreeTemp(cUnit, r2);
1977 oatFreeTemp(cUnit, r3);
1978 } else if (bb->blockType == kExitBlock) {
1979 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07001980 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07001981 /* Need to restore any FP callee saves? */
1982 if (cUnit->numFPSpills) {
1983 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1984 }
1985 if (cUnit->coreSpillMask & (1 << rLR)) {
1986 /* Unspill rLR to rPC */
1987 cUnit->coreSpillMask &= ~(1 << rLR);
1988 cUnit->coreSpillMask |= (1 << rPC);
1989 }
1990 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1991 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1992 /* We didn't pop to rPC, so must do a bv rLR */
1993 newLIR1(cUnit, kThumbBx, rLR);
1994 }
1995 }
1996
1997 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1998
1999 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07002000 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
2001 oatClobberAllRegs(cUnit);
2002 }
buzbee67bf8852011-08-17 17:51:35 -07002003
2004 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
2005 oatResetDefTracking(cUnit);
2006 }
2007
2008 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
2009 handleExtendedMethodMIR(cUnit, mir);
2010 continue;
2011 }
2012
2013 cUnit->currentDalvikOffset = mir->offset;
2014
2015 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2016 InstructionFormat dalvikFormat =
2017 dexGetFormatFromOpcode(dalvikOpcode);
2018
2019 ArmLIR* boundaryLIR;
2020
2021 /* Mark the beginning of a Dalvik instruction for line tracking */
2022 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
2023 (int) oatGetDalvikDisassembly(
2024 &mir->dalvikInsn, ""));
2025 /* Remember the first LIR for this block */
2026 if (headLIR == NULL) {
2027 headLIR = boundaryLIR;
2028 /* Set the first boundaryLIR as a scheduling barrier */
2029 headLIR->defMask = ENCODE_ALL;
2030 }
2031
2032 /* Don't generate the SSA annotation unless verbose mode is on */
2033 if (cUnit->printMe && mir->ssaRep) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -08002034 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
buzbee67bf8852011-08-17 17:51:35 -07002035 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
2036 }
2037
2038 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
2039
2040 if (notHandled) {
2041 char buf[100];
2042 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
2043 mir->offset,
2044 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
2045 dalvikFormat);
2046 LOG(FATAL) << buf;
2047 }
2048 }
2049
2050 if (headLIR) {
2051 /*
2052 * Eliminate redundant loads/stores and delay stores into later
2053 * slots
2054 */
2055 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
2056 cUnit->lastLIRInsn);
2057
2058 /*
2059 * Generate an unconditional branch to the fallthrough block.
2060 */
2061 if (bb->fallThrough) {
2062 genUnconditionalBranch(cUnit,
2063 &labelList[bb->fallThrough->id]);
2064 }
2065 }
2066 return false;
2067}
2068
2069/*
2070 * Nop any unconditional branches that go to the next instruction.
2071 * Note: new redundant branches may be inserted later, and we'll
2072 * use a check in final instruction assembly to nop those out.
2073 */
2074void removeRedundantBranches(CompilationUnit* cUnit)
2075{
2076 ArmLIR* thisLIR;
2077
2078 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2079 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2080 thisLIR = NEXT_LIR(thisLIR)) {
2081
2082 /* Branch to the next instruction */
2083 if ((thisLIR->opcode == kThumbBUncond) ||
2084 (thisLIR->opcode == kThumb2BUncond)) {
2085 ArmLIR* nextLIR = thisLIR;
2086
2087 while (true) {
2088 nextLIR = NEXT_LIR(nextLIR);
2089
2090 /*
2091 * Is the branch target the next instruction?
2092 */
2093 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2094 thisLIR->flags.isNop = true;
2095 break;
2096 }
2097
2098 /*
2099 * Found real useful stuff between the branch and the target.
2100 * Need to explicitly check the lastLIRInsn here because it
2101 * might be the last real instruction.
2102 */
2103 if (!isPseudoOpcode(nextLIR->opcode) ||
2104 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2105 break;
2106 }
2107 }
2108 }
2109}
2110
buzbeeed3e9302011-09-23 17:34:19 -07002111STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002112{
2113 ArmLIR** suspendLabel =
2114 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2115 int numElems = cUnit->suspendLaunchpads.numUsed;
2116
2117 for (int i = 0; i < numElems; i++) {
2118 /* TUNING: move suspend count load into helper */
2119 ArmLIR* lab = suspendLabel[i];
2120 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2121 cUnit->currentDalvikOffset = lab->operands[1];
2122 oatAppendLIR(cUnit, (LIR *)lab);
2123 loadWordDisp(cUnit, rSELF,
2124 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2125 loadWordDisp(cUnit, rSELF,
2126 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2127 opReg(cUnit, kOpBlx, rLR);
2128 genUnconditionalBranch(cUnit, resumeLab);
2129 }
2130}
2131
buzbeeed3e9302011-09-23 17:34:19 -07002132STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002133{
2134 ArmLIR** throwLabel =
2135 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2136 int numElems = cUnit->throwLaunchpads.numUsed;
2137 int i;
2138
2139 for (i = 0; i < numElems; i++) {
2140 ArmLIR* lab = throwLabel[i];
2141 cUnit->currentDalvikOffset = lab->operands[1];
2142 oatAppendLIR(cUnit, (LIR *)lab);
2143 int funcOffset = 0;
2144 int v1 = lab->operands[2];
2145 int v2 = lab->operands[3];
2146 switch(lab->operands[0]) {
2147 case kArmThrowNullPointer:
2148 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2149 break;
2150 case kArmThrowArrayBounds:
2151 if (v2 != r0) {
2152 genRegCopy(cUnit, r0, v1);
2153 genRegCopy(cUnit, r1, v2);
2154 } else {
2155 if (v1 == r1) {
2156 genRegCopy(cUnit, r12, v1);
2157 genRegCopy(cUnit, r1, v2);
2158 genRegCopy(cUnit, r0, r12);
2159 } else {
2160 genRegCopy(cUnit, r1, v2);
2161 genRegCopy(cUnit, r0, v1);
2162 }
2163 }
2164 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2165 break;
2166 case kArmThrowDivZero:
2167 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2168 break;
2169 case kArmThrowVerificationError:
2170 loadConstant(cUnit, r0, v1);
2171 loadConstant(cUnit, r1, v2);
2172 funcOffset =
2173 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2174 break;
2175 case kArmThrowNegArraySize:
2176 genRegCopy(cUnit, r0, v1);
2177 funcOffset =
2178 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2179 break;
buzbee5ade1d22011-09-09 14:44:52 -07002180 case kArmThrowNoSuchMethod:
2181 genRegCopy(cUnit, r0, v1);
2182 funcOffset =
2183 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2184 break;
buzbeeec5adf32011-09-11 15:25:43 -07002185 case kArmThrowStackOverflow:
2186 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002187 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002188 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002189 opRegImm(cUnit, kOpAdd, rSP,
2190 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002191 break;
buzbee5ade1d22011-09-09 14:44:52 -07002192 default:
2193 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2194 }
2195 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002196 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002197 }
2198}
2199
buzbee67bf8852011-08-17 17:51:35 -07002200void oatMethodMIR2LIR(CompilationUnit* cUnit)
2201{
2202 /* Used to hold the labels of each block */
2203 cUnit->blockLabelList =
2204 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2205
2206 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2207 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002208 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002209
2210 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002211
2212 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002213}
2214
2215/* Common initialization routine for an architecture family */
2216bool oatArchInit()
2217{
2218 int i;
2219
2220 for (i = 0; i < kArmLast; i++) {
2221 if (EncodingMap[i].opcode != i) {
2222 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2223 " is wrong: expecting " << i << ", seeing " <<
2224 (int)EncodingMap[i].opcode;
2225 }
2226 }
2227
2228 return oatArchVariantInit();
2229}
2230
2231/* Needed by the Assembler */
2232void oatSetupResourceMasks(ArmLIR* lir)
2233{
2234 setupResourceMasks(lir);
2235}
2236
2237/* Needed by the ld/st optmizatons */
2238ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2239{
2240 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2241}
2242
2243/* Needed by the register allocator */
2244ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2245{
2246 return genRegCopy(cUnit, rDest, rSrc);
2247}
2248
2249/* Needed by the register allocator */
2250void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2251 int srcLo, int srcHi)
2252{
2253 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2254}
2255
2256void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2257 int displacement, int rSrc, OpSize size)
2258{
2259 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2260}
2261
2262void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2263 int displacement, int rSrcLo, int rSrcHi)
2264{
2265 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2266}