blob: 2edd3986a7d4dc006f960fbb21a93ba71a0a9346 [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;
50 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
51 loadWordDisp(cUnit, rSELF,
52 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
53 } else {
54 UNIMPLEMENTED(WARNING) << "Need to check access of '"
55 << PrettyMethod(cUnit->method)
56 << "' to unresolved type " << type_idx;
57 loadWordDisp(cUnit, rSELF,
58 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
59 }
buzbeedfd3d702011-08-28 12:56:51 -070060 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -070061 loadConstant(cUnit, r0, type_idx); // arg0 <- type_id
buzbeedfd3d702011-08-28 12:56:51 -070062 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070063 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070064 RegLocation rlResult = oatGetReturn(cUnit);
65 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070066}
67
68/*
69 * Similar to genNewArray, but with post-allocation initialization.
70 * Verifier guarantees we're dealing with an array class. Current
71 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
72 * Current code also throws internal unimp if not 'L', '[' or 'I'.
73 */
buzbeeed3e9302011-09-23 17:34:19 -070074STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070075{
76 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070077 int elems = dInsn->vA;
78 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070079 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070080 loadWordDisp(cUnit, rSELF,
Elliott Hughesb408de72011-10-04 14:35:05 -070081 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
Ian Rogers28ad40d2011-10-27 15:19:26 -070082 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, typeId)) {
83 UNIMPLEMENTED(WARNING) << "Need to check access of '" << PrettyMethod(cUnit->method)
84 << "' to unresolved type " << typeId;
85 }
buzbeedfd3d702011-08-28 12:56:51 -070086 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
87 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
88 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070089 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070090 /*
buzbeedfd3d702011-08-28 12:56:51 -070091 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
92 * return region. Because AllocFromCode placed the new array
93 * in r0, we'll just lock it into place. When debugger support is
94 * added, it may be necessary to additionally copy all return
95 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070096 */
buzbee67bf8852011-08-17 17:51:35 -070097 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070098
buzbee67bf8852011-08-17 17:51:35 -070099 // Having a range of 0 is legal
100 if (isRange && (dInsn->vA > 0)) {
101 /*
102 * Bit of ugliness here. We're going generate a mem copy loop
103 * on the register range, but it is possible that some regs
104 * in the range have been promoted. This is unlikely, but
105 * before generating the copy, we'll just force a flush
106 * of any regs in the source range that have been promoted to
107 * home location.
108 */
109 for (unsigned int i = 0; i < dInsn->vA; i++) {
110 RegLocation loc = oatUpdateLoc(cUnit,
111 oatGetSrc(cUnit, mir, i));
112 if (loc.location == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -0700113 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
114 loc.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700115 }
116 }
117 /*
118 * TUNING note: generated code here could be much improved, but
119 * this is an uncommon operation and isn't especially performance
120 * critical.
121 */
122 int rSrc = oatAllocTemp(cUnit);
123 int rDst = oatAllocTemp(cUnit);
124 int rIdx = oatAllocTemp(cUnit);
125 int rVal = rLR; // Using a lot of temps, rLR is known free here
126 // Set up source pointer
127 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
buzbee67bc2362011-10-11 18:08:40 -0700128 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
129 oatSRegOffset(cUnit, rlFirst.sRegLow));
buzbee67bf8852011-08-17 17:51:35 -0700130 // Set up the target pointer
131 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700132 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700133 // Set up the loop counter (known to be > 0)
buzbee31813452011-10-16 14:33:08 -0700134 loadConstant(cUnit, rIdx, dInsn->vA - 1);
buzbee67bf8852011-08-17 17:51:35 -0700135 // Generate the copy loop. Going backwards for convenience
136 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
137 target->defMask = ENCODE_ALL;
138 // Copy next element
139 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
140 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
141 // Use setflags encoding here
142 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee31813452011-10-16 14:33:08 -0700143 ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
buzbee67bf8852011-08-17 17:51:35 -0700144 branch->generic.target = (LIR*)target;
145 } else if (!isRange) {
146 // TUNING: interleave
147 for (unsigned int i = 0; i < dInsn->vA; i++) {
148 RegLocation rlArg = loadValue(cUnit,
149 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700150 storeBaseDisp(cUnit, r0,
151 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700152 i * 4, rlArg.lowReg, kWord);
153 // If the loadValue caused a temp to be allocated, free it
154 if (oatIsTemp(cUnit, rlArg.lowReg)) {
155 oatFreeTemp(cUnit, rlArg.lowReg);
156 }
157 }
158 }
159}
160
Brian Carlstrom845490b2011-09-19 15:56:53 -0700161Field* FindFieldWithResolvedStaticStorage(const Method* method,
162 const uint32_t fieldIdx,
163 uint32_t& resolvedTypeIdx) {
164 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
165 Field* field = class_linker->ResolveField(fieldIdx, method, true);
166 if (field == NULL) {
167 return NULL;
168 }
169 const art::DexFile& dex_file = class_linker->
170 FindDexFile(method->GetDeclaringClass()->GetDexCache());
171 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
172 int type_idx = field_id.class_idx_;
173 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
174 // Check if storage class is the same as class referred to by type idx.
175 // They may not be if the FieldId refers a subclass, but storage is in super
176 if (field->GetDeclaringClass() == klass) {
177 resolvedTypeIdx = type_idx;
178 return field;
179 }
180 // See if we can find a dex reference for the storage class.
181 // we may not if the dex file never references the super class,
182 // but usually it will.
183 std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
184 for (size_t type_idx = 0; type_idx < dex_file.NumTypeIds(); type_idx++) {
185 const art::DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
186 if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
187 resolvedTypeIdx = type_idx;
188 return field;
189 }
190 }
191 return NULL; // resort to slow path
192}
193
buzbeeed3e9302011-09-23 17:34:19 -0700194STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700195{
buzbeee1931742011-08-28 21:15:53 -0700196 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
197 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700198 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700199 uint32_t typeIdx;
200 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700201 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700202 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700203 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700204 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700205 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
206 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700207 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
208 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
209 loadCurrMethodDirect(cUnit, r1);
210 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700211 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700212 } else {
buzbee1da522d2011-09-04 11:22:20 -0700213 // fast path
214 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700215 // Using fixed register to sync with slow path
216 int rMethod = r1;
217 oatLockTemp(cUnit, rMethod);
218 loadCurrMethodDirect(cUnit, rMethod);
219 int rBase = r0;
220 oatLockTemp(cUnit, rBase);
221 loadWordDisp(cUnit, rMethod,
222 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
223 rBase);
224 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
225 sizeof(int32_t*)* typeIdx, rBase);
226 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700227 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700228 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
229 loadWordDisp(cUnit, rSELF,
230 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
231 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700232 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700233 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
234 skipTarget->defMask = ENCODE_ALL;
235 branchOver->generic.target = (LIR*)skipTarget;
236 rlSrc = oatGetSrc(cUnit, mir, 0);
237 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700238#if ANDROID_SMP != 0
239 if (field->IsVolatile()) {
240 oatGenMemBarrier(cUnit, kST);
241 }
242#endif
buzbee1da522d2011-09-04 11:22:20 -0700243 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700244#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700245 if (field->IsVolatile()) {
246 oatGenMemBarrier(cUnit, kSY);
247 }
buzbee67bf8852011-08-17 17:51:35 -0700248#endif
buzbee1da522d2011-09-04 11:22:20 -0700249 if (isObject) {
250 markGCCard(cUnit, rlSrc.lowReg, rBase);
251 }
252 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700253 }
buzbee67bf8852011-08-17 17:51:35 -0700254}
255
buzbeeed3e9302011-09-23 17:34:19 -0700256STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700257{
buzbee1da522d2011-09-04 11:22:20 -0700258 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700259 uint32_t typeIdx;
260 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700261 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700262#if ANDROID_SMP != 0
263 bool isVolatile = (field == NULL) || field->IsVolatile();
264#else
265 bool isVolatile = false;
266#endif
267 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700268 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700269 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700270 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
271 loadCurrMethodDirect(cUnit, r1);
272 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700273 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700274 } else {
buzbee1da522d2011-09-04 11:22:20 -0700275 // fast path
276 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700277 // Using fixed register to sync with slow path
278 int rMethod = r1;
279 oatLockTemp(cUnit, rMethod);
280 loadCurrMethodDirect(cUnit, r1);
281 int rBase = r0;
282 oatLockTemp(cUnit, rBase);
283 loadWordDisp(cUnit, rMethod,
284 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
285 rBase);
286 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
287 sizeof(int32_t*)* typeIdx, rBase);
288 // TUNING: fast path should fall through
289 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
290 loadWordDisp(cUnit, rSELF,
291 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
292 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700293 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700294 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
295 skipTarget->defMask = ENCODE_ALL;
296 branchOver->generic.target = (LIR*)skipTarget;
297 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
298 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
299 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
300 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700301 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700302 }
buzbee67bf8852011-08-17 17:51:35 -0700303}
304
305
buzbeeed3e9302011-09-23 17:34:19 -0700306STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700307 RegLocation rlResult, RegLocation rlDest)
308{
buzbee1da522d2011-09-04 11:22:20 -0700309 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700310 uint32_t typeIdx;
311 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700312#if ANDROID_SMP != 0
313 bool isVolatile = (field == NULL) || field->IsVolatile();
314#else
315 bool isVolatile = false;
316#endif
buzbee6181f792011-09-29 11:14:04 -0700317 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700318 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700319 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700320 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700321 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
322 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700323 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700324 RegLocation rlResult = oatGetReturnWide(cUnit);
325 storeValueWide(cUnit, rlDest, rlResult);
326 } else {
buzbee1da522d2011-09-04 11:22:20 -0700327 // Fast path
328 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700329 // Using fixed register to sync with slow path
330 int rMethod = r1;
331 oatLockTemp(cUnit, rMethod);
332 loadCurrMethodDirect(cUnit, rMethod);
333 int rBase = r0;
334 oatLockTemp(cUnit, rBase);
335 loadWordDisp(cUnit, rMethod,
336 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
337 rBase);
338 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
339 sizeof(int32_t*)* typeIdx, rBase);
340 // TUNING: fast path should fall through
341 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
342 loadWordDisp(cUnit, rSELF,
343 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
344 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700345 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700346 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
347 skipTarget->defMask = ENCODE_ALL;
348 branchOver->generic.target = (LIR*)skipTarget;
349 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
350 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700351 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
352 rlResult.highReg, INVALID_SREG);
353 oatFreeTemp(cUnit, rBase);
354 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700355 }
buzbee67bf8852011-08-17 17:51:35 -0700356}
357
buzbeeed3e9302011-09-23 17:34:19 -0700358STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700359 RegLocation rlResult, RegLocation rlDest)
360{
buzbee1da522d2011-09-04 11:22:20 -0700361 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700362 uint32_t typeIdx;
363 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700364 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
365 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700366 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700367 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700368 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700369 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700370 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
371 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700372 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
373 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
374 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700375 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700376 RegLocation rlResult = oatGetReturn(cUnit);
377 storeValue(cUnit, rlDest, rlResult);
378 } else {
buzbee1da522d2011-09-04 11:22:20 -0700379 // Fast path
380 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700381 // Using fixed register to sync with slow path
382 int rMethod = r1;
383 oatLockTemp(cUnit, rMethod);
384 loadCurrMethodDirect(cUnit, rMethod);
385 int rBase = r0;
386 oatLockTemp(cUnit, rBase);
387 loadWordDisp(cUnit, rMethod,
388 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
389 rBase);
390 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
391 sizeof(int32_t*)* typeIdx, rBase);
392 // TUNING: fast path should fall through
393 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
394 loadWordDisp(cUnit, rSELF,
395 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
396 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700397 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700398 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
399 skipTarget->defMask = ENCODE_ALL;
400 branchOver->generic.target = (LIR*)skipTarget;
401 rlDest = oatGetDest(cUnit, mir, 0);
402 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700403#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700404 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700405 oatGenMemBarrier(cUnit, kSY);
406 }
buzbee67bf8852011-08-17 17:51:35 -0700407#endif
buzbee1da522d2011-09-04 11:22:20 -0700408 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
409 oatFreeTemp(cUnit, rBase);
410 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700411 }
buzbee67bf8852011-08-17 17:51:35 -0700412}
413
buzbee561227c2011-09-02 15:28:19 -0700414typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
415 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700416
417/*
418 * Bit of a hack here - in leiu of a real scheduling pass,
419 * emit the next instruction in static & direct invoke sequences.
420 */
buzbeeed3e9302011-09-23 17:34:19 -0700421STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700422 DecodedInstruction* dInsn, int state,
423 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700424{
buzbee561227c2011-09-02 15:28:19 -0700425 DCHECK(rollback == NULL);
426 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700427 switch(state) {
428 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700429 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700430 break;
buzbee561227c2011-09-02 15:28:19 -0700431 case 1: // Get method->code_and_direct_methods_
432 loadWordDisp(cUnit, r0,
433 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
434 r0);
buzbee67bf8852011-08-17 17:51:35 -0700435 break;
buzbee561227c2011-09-02 15:28:19 -0700436 case 2: // Grab target method* and target code_
437 loadWordDisp(cUnit, r0,
438 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
439 loadWordDisp(cUnit, r0,
440 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700441 break;
442 default:
443 return -1;
444 }
445 return state + 1;
446}
447
buzbee67bf8852011-08-17 17:51:35 -0700448/*
449 * Bit of a hack here - in leiu of a real scheduling pass,
450 * emit the next instruction in a virtual invoke sequence.
451 * We can use rLR as a temp prior to target address loading
452 * Note also that we'll load the first argument ("this") into
453 * r1 here rather than the standard loadArgRegs.
454 */
buzbeeed3e9302011-09-23 17:34:19 -0700455STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700456 DecodedInstruction* dInsn, int state,
457 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700458{
buzbee561227c2011-09-02 15:28:19 -0700459 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700460 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700461 /*
462 * This is the fast path in which the target virtual method is
463 * fully resolved at compile time.
464 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700465 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
466 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -0700467 CHECK(baseMethod != NULL);
468 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700469 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700470 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700471 rlArg = oatGetSrc(cUnit, mir, 0);
472 loadValueDirectFixed(cUnit, rlArg, r1);
473 break;
buzbee561227c2011-09-02 15:28:19 -0700474 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700475 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700476 // get this->klass_ [use r1, set rLR]
477 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700478 break;
buzbee561227c2011-09-02 15:28:19 -0700479 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
480 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700481 break;
buzbee561227c2011-09-02 15:28:19 -0700482 case 3: // Get target method [use rLR, set r0]
483 loadWordDisp(cUnit, rLR, (target_idx * 4) +
484 art::Array::DataOffset().Int32Value(), r0);
485 break;
486 case 4: // Get the target compiled code address [uses r0, sets rLR]
487 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700488 break;
489 default:
490 return -1;
491 }
492 return state + 1;
493}
494
buzbeeed3e9302011-09-23 17:34:19 -0700495STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700496 DecodedInstruction* dInsn, int state,
497 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700498{
499 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700500 ArmLIR* skipBranch;
501 ArmLIR* skipTarget;
502 /*
503 * This handles the case in which the base method is not fully
504 * resolved at compile time. We must generate code to test
505 * for resolution a run time, bail to the slow path if not to
506 * fill in all the tables. In the latter case, we'll restart at
507 * at the beginning of the sequence.
508 */
buzbee7b1b86d2011-08-26 18:59:10 -0700509 switch(state) {
510 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700511 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700512 break;
buzbee561227c2011-09-02 15:28:19 -0700513 case 1: // Get method->dex_cache_resolved_methods_
514 loadWordDisp(cUnit, r0,
515 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700516 break;
buzbee561227c2011-09-02 15:28:19 -0700517 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
518 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
519 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700520 break;
buzbee561227c2011-09-02 15:28:19 -0700521 case 3: // Resolved?
522 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
523 // Slowest path, bail to helper, rollback and retry
524 loadWordDisp(cUnit, rSELF,
525 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
526 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700527 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700528 genUnconditionalBranch(cUnit, rollback);
529 // Resume normal slow path
530 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
531 skipTarget->defMask = ENCODE_ALL;
532 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700533 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700534 loadBaseDisp(cUnit, mir, rLR,
535 Method::GetMethodIndexOffset().Int32Value(), r0,
536 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700537 // Load "this" [set r1]
538 rlArg = oatGetSrc(cUnit, mir, 0);
539 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700540 break;
541 case 4:
542 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700543 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700544 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700545 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700546 break;
buzbee561227c2011-09-02 15:28:19 -0700547 case 5:
548 // get this->klass_->vtable_ [usr rLR, set rLR]
549 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700550 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700551 // In load shadow fold vtable_ object header size into method_index_
552 opRegImm(cUnit, kOpAdd, r0,
553 art::Array::DataOffset().Int32Value() / 4);
554 // Get target Method*
555 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
556 break;
557 case 6: // Get the target compiled code address [uses r0, sets rLR]
558 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700559 break;
560 default:
561 return -1;
562 }
563 return state + 1;
564}
565
buzbeeed3e9302011-09-23 17:34:19 -0700566STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700567 DecodedInstruction* dInsn, int callState,
568 NextCallInsn nextCallInsn, ArmLIR* rollback,
569 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700570{
buzbeec0ecd652011-09-25 18:11:54 -0700571 int nextReg = r1;
572 int nextArg = 0;
573 if (skipThis) {
574 nextReg++;
575 nextArg++;
576 }
577 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
578 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
579 rlArg = oatUpdateRawLoc(cUnit, rlArg);
580 if (rlArg.wide && (nextReg <= r2)) {
581 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
582 nextReg++;
583 nextArg++;
584 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700585 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700586 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700587 }
buzbeec0ecd652011-09-25 18:11:54 -0700588 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700589 }
590 return callState;
591}
592
buzbee4a3164f2011-09-03 11:25:10 -0700593// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700594STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700595 DecodedInstruction* dInsn, int state,
596 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700597{
buzbee510c6052011-10-27 10:47:20 -0700598 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700599 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700600 case 0: // Load trampoline target
601 loadWordDisp(cUnit, rSELF,
602 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
603 rLR);
604 // Load r0 with method index
605 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700606 break;
buzbee67bf8852011-08-17 17:51:35 -0700607 default:
608 return -1;
609 }
610 return state + 1;
611}
612
buzbee67bf8852011-08-17 17:51:35 -0700613/*
614 * Interleave launch code for INVOKE_SUPER. See comments
615 * for nextVCallIns.
616 */
buzbeeed3e9302011-09-23 17:34:19 -0700617STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700618 DecodedInstruction* dInsn, int state,
619 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700620{
buzbee4a3164f2011-09-03 11:25:10 -0700621 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700622 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700623 /*
624 * This is the fast path in which the target virtual method is
625 * fully resolved at compile time. Note also that this path assumes
626 * that the check to verify that the target method index falls
627 * within the size of the super's vtable has been done at compile-time.
628 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700629 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
630 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700631 CHECK(baseMethod != NULL);
632 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
633 CHECK(superClass != NULL);
634 int32_t target_idx = baseMethod->GetMethodIndex();
635 CHECK(superClass->GetVTable()->GetLength() > target_idx);
636 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
637 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700638 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700639 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700640 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700641 // Load "this" [set r1]
642 rlArg = oatGetSrc(cUnit, mir, 0);
643 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700644 // Get method->declaring_class_ [use r0, set rLR]
645 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
646 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700647 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700648 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700649 break;
650 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
651 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
652 rLR);
653 break;
654 case 2: // Get ...->super_class_->vtable [u/s rLR]
655 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
656 break;
657 case 3: // Get target method [use rLR, set r0]
658 loadWordDisp(cUnit, rLR, (target_idx * 4) +
659 art::Array::DataOffset().Int32Value(), r0);
660 break;
661 case 4: // Get the target compiled code address [uses r0, sets rLR]
662 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
663 break;
buzbee67bf8852011-08-17 17:51:35 -0700664 default:
665 return -1;
666 }
buzbee4a3164f2011-09-03 11:25:10 -0700667 return state + 1;
668}
669
670/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700671STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700672 DecodedInstruction* dInsn, int state,
673 ArmLIR* rollback)
674{
buzbee4a3164f2011-09-03 11:25:10 -0700675 RegLocation rlArg;
676 ArmLIR* skipBranch;
677 ArmLIR* skipTarget;
678 int tReg;
679 /*
680 * This handles the case in which the base method is not fully
681 * resolved at compile time. We must generate code to test
682 * for resolution a run time, bail to the slow path if not to
683 * fill in all the tables. In the latter case, we'll restart at
684 * at the beginning of the sequence.
685 */
686 switch(state) {
687 case 0: // Get the current Method* [sets r0]
688 loadCurrMethodDirect(cUnit, r0);
689 break;
690 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
691 loadWordDisp(cUnit, r0,
692 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
693 break;
694 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
695 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
696 art::Array::DataOffset().Int32Value(), rLR);
697 break;
698 case 3: // Resolved?
699 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
700 // Slowest path, bail to helper, rollback and retry
701 loadWordDisp(cUnit, rSELF,
702 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
703 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700704 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700705 genUnconditionalBranch(cUnit, rollback);
706 // Resume normal slow path
707 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
708 skipTarget->defMask = ENCODE_ALL;
709 skipBranch->generic.target = (LIR*)skipTarget;
710 // Get base_method->method_index [usr rLR, set rLR]
711 loadBaseDisp(cUnit, mir, rLR,
712 Method::GetMethodIndexOffset().Int32Value(), rLR,
713 kUnsignedHalf, INVALID_SREG);
714 // Load "this" [set r1]
715 rlArg = oatGetSrc(cUnit, mir, 0);
716 loadValueDirectFixed(cUnit, rlArg, r1);
717 // Load curMethod->declaring_class_ [uses r0, sets r0]
718 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
719 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700720 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700721 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700722 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700723 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
724 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700725 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700726 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700727 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700728 // Range check, throw NSM on failure
729 tReg = oatAllocTemp(cUnit);
730 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
731 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700732 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
733 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700734 oatFreeTemp(cUnit, tReg);
735 }
buzbee6a0f7f52011-09-05 16:14:20 -0700736 // Adjust vtable_ base past object header
737 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700738 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700739 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700740 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700741 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700742 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
743 break;
744 default:
745 return -1;
746 }
buzbee67bf8852011-08-17 17:51:35 -0700747 return state + 1;
748}
749
750/*
751 * Load up to 5 arguments, the first three of which will be in
752 * r1 .. r3. On entry r0 contains the current method pointer,
753 * and as part of the load sequence, it must be replaced with
754 * the target method pointer. Note, this may also be called
755 * for "range" variants if the number of arguments is 5 or fewer.
756 */
buzbeeed3e9302011-09-23 17:34:19 -0700757STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700758 DecodedInstruction* dInsn, int callState,
759 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700760 NextCallInsn nextCallInsn, ArmLIR* rollback,
761 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700762{
763 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700764
765 /* If no arguments, just return */
766 if (dInsn->vA == 0)
767 return callState;
768
buzbee561227c2011-09-02 15:28:19 -0700769 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700770
buzbeec0ecd652011-09-25 18:11:54 -0700771 DCHECK_LE(dInsn->vA, 5U);
772 if (dInsn->vA > 3) {
773 uint32_t nextUse = 3;
774 //Detect special case of wide arg spanning arg3/arg4
775 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
776 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
777 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
778 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
779 rlUse2.wide) {
780 int reg;
781 // Wide spans, we need the 2nd half of uses[2].
782 rlArg = oatUpdateLocWide(cUnit, rlUse2);
783 if (rlArg.location == kLocPhysReg) {
784 reg = rlArg.highReg;
785 } else {
786 // r2 & r3 can safely be used here
787 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700788 loadWordDisp(cUnit, rSP,
789 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
buzbeec0ecd652011-09-25 18:11:54 -0700790 callState = nextCallInsn(cUnit, mir, dInsn, callState,
791 rollback);
792 }
793 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
794 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
795 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
796 nextUse++;
797 }
798 // Loop through the rest
799 while (nextUse < dInsn->vA) {
800 int lowReg;
801 int highReg;
802 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
803 rlArg = oatUpdateRawLoc(cUnit, rlArg);
804 if (rlArg.location == kLocPhysReg) {
805 lowReg = rlArg.lowReg;
806 highReg = rlArg.highReg;
807 } else {
808 lowReg = r2;
809 highReg = r3;
810 if (rlArg.wide) {
811 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
812 } else {
813 loadValueDirectFixed(cUnit, rlArg, lowReg);
814 }
815 callState = nextCallInsn(cUnit, mir, dInsn, callState,
816 rollback);
817 }
818 int outsOffset = (nextUse + 1) * 4;
819 if (rlArg.wide) {
820 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
821 nextUse += 2;
822 } else {
823 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
824 nextUse++;
825 }
buzbee561227c2011-09-02 15:28:19 -0700826 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700827 }
buzbee67bf8852011-08-17 17:51:35 -0700828 }
829
buzbeec0ecd652011-09-25 18:11:54 -0700830 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
831 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700832
buzbee67bf8852011-08-17 17:51:35 -0700833 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700834 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700835 }
836 return callState;
837}
838
839/*
840 * May have 0+ arguments (also used for jumbo). Note that
841 * source virtual registers may be in physical registers, so may
842 * need to be flushed to home location before copying. This
843 * applies to arg3 and above (see below).
844 *
845 * Two general strategies:
846 * If < 20 arguments
847 * Pass args 3-18 using vldm/vstm block copy
848 * Pass arg0, arg1 & arg2 in r1-r3
849 * If 20+ arguments
850 * Pass args arg19+ using memcpy block copy
851 * Pass arg0, arg1 & arg2 in r1-r3
852 *
853 */
buzbeeed3e9302011-09-23 17:34:19 -0700854STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700855 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700856 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700857 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700858{
859 int firstArg = dInsn->vC;
860 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700861
buzbee67bf8852011-08-17 17:51:35 -0700862 // If we can treat it as non-range (Jumbo ops will use range form)
863 if (numArgs <= 5)
864 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700865 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700866 /*
867 * Make sure range list doesn't span the break between in normal
868 * Dalvik vRegs and the ins.
869 */
buzbee1b4c8592011-08-31 10:43:51 -0700870 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700871 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700872 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
873 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700874 }
875
876 /*
877 * First load the non-register arguments. Both forms expect all
878 * of the source arguments to be in their home frame location, so
879 * scan the sReg names and flush any that have been promoted to
880 * frame backing storage.
881 */
882 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700883 for (int nextArg = 0; nextArg < numArgs;) {
884 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700885 if (loc.wide) {
886 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700887 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700888 storeBaseDispWide(cUnit, rSP,
889 oatSRegOffset(cUnit, loc.sRegLow),
890 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700891 }
buzbeec0ecd652011-09-25 18:11:54 -0700892 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700893 } else {
894 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700895 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700896 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
897 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700898 }
buzbeec0ecd652011-09-25 18:11:54 -0700899 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700900 }
901 }
902
buzbee67bc2362011-10-11 18:08:40 -0700903 int startOffset = oatSRegOffset(cUnit,
904 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700905 int outsOffset = 4 /* Method* */ + (3 * 4);
906 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700907 // Generate memcpy
908 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
909 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700910 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
911 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700912 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700913 // Restore Method*
914 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700915 } else {
916 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700917 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700918 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700919 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700920 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
921 //TUNING: loosen barrier
922 ld->defMask = ENCODE_ALL;
923 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700924 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700925 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700926 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700927 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
928 setMemRefType(st, false /* isLoad */, kDalvikReg);
929 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700930 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700931 }
932
buzbeec0ecd652011-09-25 18:11:54 -0700933 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
934 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700935
buzbee561227c2011-09-02 15:28:19 -0700936 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee99f27232011-10-05 12:56:36 -0700937 if (pcrLabel) {
938 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
939 }
buzbee67bf8852011-08-17 17:51:35 -0700940 return callState;
941}
942
buzbee2a475e72011-09-07 17:19:17 -0700943// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700944STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700945{
946 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
947 loadWordDisp(cUnit, rSELF,
948 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
949 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
950 target->defMask = -1;
951 branchOver->generic.target = (LIR*)target;
952}
buzbee2a475e72011-09-07 17:19:17 -0700953
buzbeeed3e9302011-09-23 17:34:19 -0700954STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700955 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700956{
957 DecodedInstruction* dInsn = &mir->dalvikInsn;
958 int callState = 0;
959 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700960 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700961 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700962 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700963
buzbee109bd6a2011-09-06 13:58:41 -0700964 // Explicit register usage
965 oatLockCallTemps(cUnit);
966
buzbee99f27232011-10-05 12:56:36 -0700967 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
968 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
969 int idx = mir->dalvikInsn.vB;
970 Method* target = cUnit->method->GetDexCacheResolvedMethods()->Get(idx);
971 if (target) {
972 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
973 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
974 loadValueDirectFixed(cUnit, rlArg, r0);
975 loadWordDisp(cUnit, rSELF,
976 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
977 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
978 opReg(cUnit, kOpBlx, rLR);
979 oatClobberCalleeSave(cUnit);
980 return;
981 }
982 }
983 }
984
buzbee561227c2011-09-02 15:28:19 -0700985 if (range) {
986 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700987 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700988 } else {
989 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700990 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700991 }
buzbee67bf8852011-08-17 17:51:35 -0700992 // Finish up any of the call sequence not interleaved in arg loading
993 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700994 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700995 }
buzbeece302932011-10-04 14:32:18 -0700996 if (DISPLAY_MISSING_TARGETS) {
997 genShowTarget(cUnit);
998 }
buzbeeec5adf32011-09-11 15:25:43 -0700999 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001000 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001001}
1002
buzbee4a3164f2011-09-03 11:25:10 -07001003/*
1004 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
1005 * which will locate the target and continue on via a tail call.
1006 */
buzbeeed3e9302011-09-23 17:34:19 -07001007STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001008{
1009 DecodedInstruction* dInsn = &mir->dalvikInsn;
1010 int callState = 0;
1011 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -07001012 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001013
1014 // Explicit register usage
1015 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001016 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -07001017 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001018 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
1019 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001020 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -07001021 false);
buzbee67bf8852011-08-17 17:51:35 -07001022 else
1023 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -07001024 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -07001025 // Finish up any of the call sequence not interleaved in arg loading
1026 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001027 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001028 }
buzbeece302932011-10-04 14:32:18 -07001029 if (DISPLAY_MISSING_TARGETS) {
1030 genShowTarget(cUnit);
1031 }
buzbeeec5adf32011-09-11 15:25:43 -07001032 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001033 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001034}
1035
buzbeeed3e9302011-09-23 17:34:19 -07001036STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001037{
1038 DecodedInstruction* dInsn = &mir->dalvikInsn;
1039 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001040 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001041 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1042 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -07001043 NextCallInsn nextCallInsn;
1044 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001045 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001046
1047 // Explicit register usage
1048 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001049 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001050 Thread* thread = Thread::Current();
1051 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1052 thread->ClearException();
1053 }
buzbee4a3164f2011-09-03 11:25:10 -07001054 fastPath = false;
1055 } else {
1056 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
1057 if (superClass == NULL) {
1058 fastPath = false;
1059 } else {
1060 int32_t target_idx = baseMethod->GetMethodIndex();
1061 if (superClass->GetVTable()->GetLength() <= target_idx) {
1062 fastPath = false;
1063 } else {
1064 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1065 }
1066 }
1067 }
1068 if (fastPath) {
1069 nextCallInsn = nextSuperCallInsn;
1070 rollback = NULL;
1071 } else {
1072 nextCallInsn = nextSuperCallInsnSP;
1073 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1074 rollback->defMask = -1;
1075 }
buzbee67bf8852011-08-17 17:51:35 -07001076 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001077 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001078 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001079 else
buzbeec0ecd652011-09-25 18:11:54 -07001080 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001081 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001082 // Finish up any of the call sequence not interleaved in arg loading
1083 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001084 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001085 }
buzbeece302932011-10-04 14:32:18 -07001086 if (DISPLAY_MISSING_TARGETS) {
1087 genShowTarget(cUnit);
1088 }
buzbeeec5adf32011-09-11 15:25:43 -07001089 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001090 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001091}
1092
buzbeeed3e9302011-09-23 17:34:19 -07001093STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001094{
1095 DecodedInstruction* dInsn = &mir->dalvikInsn;
1096 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001097 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001098 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1099 Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -07001100 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001101 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee7b1b86d2011-08-26 18:59:10 -07001102
buzbee109bd6a2011-09-06 13:58:41 -07001103 // Explicit register usage
1104 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001105 if (SLOW_INVOKE_PATH || method == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001106 Thread* thread = Thread::Current();
1107 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1108 thread->ClearException();
1109 }
buzbee561227c2011-09-02 15:28:19 -07001110 // Slow path
1111 nextCallInsn = nextVCallInsnSP;
1112 // If we need a slow-path callout, we'll restart here
1113 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1114 rollback->defMask = -1;
1115 } else {
1116 // Fast path
1117 nextCallInsn = nextVCallInsn;
1118 rollback = NULL;
1119 }
buzbee67bf8852011-08-17 17:51:35 -07001120 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001121 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001122 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001123 else
buzbeec0ecd652011-09-25 18:11:54 -07001124 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001125 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001126 // Finish up any of the call sequence not interleaved in arg loading
1127 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001128 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001129 }
buzbeece302932011-10-04 14:32:18 -07001130 if (DISPLAY_MISSING_TARGETS) {
1131 genShowTarget(cUnit);
1132 }
buzbeeec5adf32011-09-11 15:25:43 -07001133 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001134 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001135}
1136
buzbeeed3e9302011-09-23 17:34:19 -07001137STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001138 BasicBlock* bb, ArmLIR* labelList)
1139{
1140 bool res = false; // Assume success
1141 RegLocation rlSrc[3];
1142 RegLocation rlDest = badLoc;
1143 RegLocation rlResult = badLoc;
1144 Opcode opcode = mir->dalvikInsn.opcode;
1145
1146 /* Prep Src and Dest locations */
1147 int nextSreg = 0;
1148 int nextLoc = 0;
1149 int attrs = oatDataFlowAttributes[opcode];
1150 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1151 if (attrs & DF_UA) {
1152 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1153 nextSreg++;
1154 } else if (attrs & DF_UA_WIDE) {
1155 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1156 nextSreg + 1);
1157 nextSreg+= 2;
1158 }
1159 if (attrs & DF_UB) {
1160 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1161 nextSreg++;
1162 } else if (attrs & DF_UB_WIDE) {
1163 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1164 nextSreg + 1);
1165 nextSreg+= 2;
1166 }
1167 if (attrs & DF_UC) {
1168 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1169 } else if (attrs & DF_UC_WIDE) {
1170 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1171 nextSreg + 1);
1172 }
1173 if (attrs & DF_DA) {
1174 rlDest = oatGetDest(cUnit, mir, 0);
1175 } else if (attrs & DF_DA_WIDE) {
1176 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1177 }
1178
1179 switch(opcode) {
1180 case OP_NOP:
1181 break;
1182
1183 case OP_MOVE_EXCEPTION:
1184 int exOffset;
1185 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001186 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001187 resetReg = oatAllocTemp(cUnit);
1188 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1189 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1190 loadConstant(cUnit, resetReg, 0);
1191 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1192 storeValue(cUnit, rlDest, rlResult);
1193 break;
1194
1195 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -07001196 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001197 break;
1198
1199 case OP_RETURN:
1200 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -07001201 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001202 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001203 break;
1204
1205 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -07001206 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001207 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001208 break;
1209
1210 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001211 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001212 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001213 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001214 break;
1215
1216 case OP_MOVE_RESULT:
1217 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001218 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001219 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001220 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001221 break;
1222
1223 case OP_MOVE:
1224 case OP_MOVE_OBJECT:
1225 case OP_MOVE_16:
1226 case OP_MOVE_OBJECT_16:
1227 case OP_MOVE_FROM16:
1228 case OP_MOVE_OBJECT_FROM16:
1229 storeValue(cUnit, rlDest, rlSrc[0]);
1230 break;
1231
1232 case OP_MOVE_WIDE:
1233 case OP_MOVE_WIDE_16:
1234 case OP_MOVE_WIDE_FROM16:
1235 storeValueWide(cUnit, rlDest, rlSrc[0]);
1236 break;
1237
1238 case OP_CONST:
1239 case OP_CONST_4:
1240 case OP_CONST_16:
1241 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1242 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1243 storeValue(cUnit, rlDest, rlResult);
1244 break;
1245
1246 case OP_CONST_HIGH16:
1247 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1248 loadConstantNoClobber(cUnit, rlResult.lowReg,
1249 mir->dalvikInsn.vB << 16);
1250 storeValue(cUnit, rlDest, rlResult);
1251 break;
1252
1253 case OP_CONST_WIDE_16:
1254 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001255 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1256 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1257 mir->dalvikInsn.vB,
1258 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001259 storeValueWide(cUnit, rlDest, rlResult);
1260 break;
1261
1262 case OP_CONST_WIDE:
1263 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1264 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001265 mir->dalvikInsn.vB_wide & 0xffffffff,
1266 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001267 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001268 break;
1269
1270 case OP_CONST_WIDE_HIGH16:
1271 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1272 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1273 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001274 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001275 break;
1276
1277 case OP_MONITOR_ENTER:
1278 genMonitorEnter(cUnit, mir, rlSrc[0]);
1279 break;
1280
1281 case OP_MONITOR_EXIT:
1282 genMonitorExit(cUnit, mir, rlSrc[0]);
1283 break;
1284
1285 case OP_CHECK_CAST:
1286 genCheckCast(cUnit, mir, rlSrc[0]);
1287 break;
1288
1289 case OP_INSTANCE_OF:
1290 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1291 break;
1292
1293 case OP_NEW_INSTANCE:
1294 genNewInstance(cUnit, mir, rlDest);
1295 break;
1296
1297 case OP_THROW:
1298 genThrow(cUnit, mir, rlSrc[0]);
1299 break;
1300
buzbee5ade1d22011-09-09 14:44:52 -07001301 case OP_THROW_VERIFICATION_ERROR:
1302 loadWordDisp(cUnit, rSELF,
1303 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1304 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1305 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001306 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001307 break;
1308
buzbee67bf8852011-08-17 17:51:35 -07001309 case OP_ARRAY_LENGTH:
1310 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001311 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001312 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001313 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001314 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1315 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1316 rlResult.lowReg);
1317 storeValue(cUnit, rlDest, rlResult);
1318 break;
1319
1320 case OP_CONST_STRING:
1321 case OP_CONST_STRING_JUMBO:
1322 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1323 break;
1324
1325 case OP_CONST_CLASS:
1326 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1327 break;
1328
1329 case OP_FILL_ARRAY_DATA:
1330 genFillArrayData(cUnit, mir, rlSrc[0]);
1331 break;
1332
1333 case OP_FILLED_NEW_ARRAY:
1334 genFilledNewArray(cUnit, mir, false /* not range */);
1335 break;
1336
1337 case OP_FILLED_NEW_ARRAY_RANGE:
1338 genFilledNewArray(cUnit, mir, true /* range */);
1339 break;
1340
1341 case OP_NEW_ARRAY:
1342 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1343 break;
1344
1345 case OP_GOTO:
1346 case OP_GOTO_16:
1347 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001348 if (bb->taken->startOffset <= mir->offset) {
1349 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001350 }
1351 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1352 break;
1353
1354 case OP_PACKED_SWITCH:
1355 genPackedSwitch(cUnit, mir, rlSrc[0]);
1356 break;
1357
1358 case OP_SPARSE_SWITCH:
1359 genSparseSwitch(cUnit, mir, rlSrc[0]);
1360 break;
1361
1362 case OP_CMPL_FLOAT:
1363 case OP_CMPG_FLOAT:
1364 case OP_CMPL_DOUBLE:
1365 case OP_CMPG_DOUBLE:
1366 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1367 break;
1368
1369 case OP_CMP_LONG:
1370 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1371 break;
1372
1373 case OP_IF_EQ:
1374 case OP_IF_NE:
1375 case OP_IF_LT:
1376 case OP_IF_GE:
1377 case OP_IF_GT:
1378 case OP_IF_LE: {
1379 bool backwardBranch;
1380 ArmConditionCode cond;
1381 backwardBranch = (bb->taken->startOffset <= mir->offset);
1382 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001383 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001384 }
1385 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1386 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1387 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1388 switch(opcode) {
1389 case OP_IF_EQ:
1390 cond = kArmCondEq;
1391 break;
1392 case OP_IF_NE:
1393 cond = kArmCondNe;
1394 break;
1395 case OP_IF_LT:
1396 cond = kArmCondLt;
1397 break;
1398 case OP_IF_GE:
1399 cond = kArmCondGe;
1400 break;
1401 case OP_IF_GT:
1402 cond = kArmCondGt;
1403 break;
1404 case OP_IF_LE:
1405 cond = kArmCondLe;
1406 break;
1407 default:
1408 cond = (ArmConditionCode)0;
1409 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1410 }
1411 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1412 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1413 break;
1414 }
1415
1416 case OP_IF_EQZ:
1417 case OP_IF_NEZ:
1418 case OP_IF_LTZ:
1419 case OP_IF_GEZ:
1420 case OP_IF_GTZ:
1421 case OP_IF_LEZ: {
1422 bool backwardBranch;
1423 ArmConditionCode cond;
1424 backwardBranch = (bb->taken->startOffset <= mir->offset);
1425 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001426 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001427 }
1428 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1429 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1430 switch(opcode) {
1431 case OP_IF_EQZ:
1432 cond = kArmCondEq;
1433 break;
1434 case OP_IF_NEZ:
1435 cond = kArmCondNe;
1436 break;
1437 case OP_IF_LTZ:
1438 cond = kArmCondLt;
1439 break;
1440 case OP_IF_GEZ:
1441 cond = kArmCondGe;
1442 break;
1443 case OP_IF_GTZ:
1444 cond = kArmCondGt;
1445 break;
1446 case OP_IF_LEZ:
1447 cond = kArmCondLe;
1448 break;
1449 default:
1450 cond = (ArmConditionCode)0;
1451 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1452 }
1453 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1454 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1455 break;
1456 }
1457
1458 case OP_AGET_WIDE:
1459 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1460 break;
1461 case OP_AGET:
1462 case OP_AGET_OBJECT:
1463 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1464 break;
1465 case OP_AGET_BOOLEAN:
1466 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1467 rlDest, 0);
1468 break;
1469 case OP_AGET_BYTE:
1470 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1471 break;
1472 case OP_AGET_CHAR:
1473 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1474 rlDest, 1);
1475 break;
1476 case OP_AGET_SHORT:
1477 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1478 break;
1479 case OP_APUT_WIDE:
1480 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1481 break;
1482 case OP_APUT:
1483 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1484 break;
1485 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001486 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001487 break;
1488 case OP_APUT_SHORT:
1489 case OP_APUT_CHAR:
1490 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1491 rlSrc[0], 1);
1492 break;
1493 case OP_APUT_BYTE:
1494 case OP_APUT_BOOLEAN:
1495 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1496 rlSrc[0], 0);
1497 break;
1498
1499 case OP_IGET_WIDE:
1500 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001501 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001502 break;
1503
1504 case OP_IGET:
1505 case OP_IGET_VOLATILE:
1506 case OP_IGET_OBJECT:
1507 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001508 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001509 break;
1510
1511 case OP_IGET_BOOLEAN:
1512 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001513 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001514 break;
1515
1516 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001517 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001518 break;
1519
1520 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001521 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001522 break;
1523
1524 case OP_IPUT_WIDE:
1525 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001526 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001527 break;
1528
1529 case OP_IPUT_OBJECT:
1530 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001531 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001532 break;
1533
1534 case OP_IPUT:
1535 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001536 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001537 break;
1538
1539 case OP_IPUT_BOOLEAN:
1540 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001541 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001542 break;
1543
1544 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001545 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001546 break;
1547
1548 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001549 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001550 break;
1551
1552 case OP_SGET:
1553 case OP_SGET_OBJECT:
1554 case OP_SGET_BOOLEAN:
1555 case OP_SGET_BYTE:
1556 case OP_SGET_CHAR:
1557 case OP_SGET_SHORT:
1558 genSget(cUnit, mir, rlResult, rlDest);
1559 break;
1560
1561 case OP_SGET_WIDE:
1562 genSgetWide(cUnit, mir, rlResult, rlDest);
1563 break;
1564
1565 case OP_SPUT:
1566 case OP_SPUT_OBJECT:
1567 case OP_SPUT_BOOLEAN:
1568 case OP_SPUT_BYTE:
1569 case OP_SPUT_CHAR:
1570 case OP_SPUT_SHORT:
1571 genSput(cUnit, mir, rlSrc[0]);
1572 break;
1573
1574 case OP_SPUT_WIDE:
1575 genSputWide(cUnit, mir, rlSrc[0]);
1576 break;
1577
1578 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001579 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1580 true /*range*/);
1581 break;
buzbee67bf8852011-08-17 17:51:35 -07001582 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001583 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1584 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001585 break;
1586
1587 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001588 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1589 false /*range*/);
1590 break;
buzbee67bf8852011-08-17 17:51:35 -07001591 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001592 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1593 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001594 break;
1595
1596 case OP_INVOKE_VIRTUAL:
1597 case OP_INVOKE_VIRTUAL_RANGE:
1598 genInvokeVirtual(cUnit, mir);
1599 break;
1600
1601 case OP_INVOKE_SUPER:
1602 case OP_INVOKE_SUPER_RANGE:
1603 genInvokeSuper(cUnit, mir);
1604 break;
1605
1606 case OP_INVOKE_INTERFACE:
1607 case OP_INVOKE_INTERFACE_RANGE:
1608 genInvokeInterface(cUnit, mir);
1609 break;
1610
1611 case OP_NEG_INT:
1612 case OP_NOT_INT:
1613 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1614 break;
1615
1616 case OP_NEG_LONG:
1617 case OP_NOT_LONG:
1618 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1619 break;
1620
1621 case OP_NEG_FLOAT:
1622 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1623 break;
1624
1625 case OP_NEG_DOUBLE:
1626 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1627 break;
1628
1629 case OP_INT_TO_LONG:
1630 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1631 if (rlSrc[0].location == kLocPhysReg) {
1632 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1633 } else {
1634 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1635 }
1636 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1637 rlResult.lowReg, 31);
1638 storeValueWide(cUnit, rlDest, rlResult);
1639 break;
1640
1641 case OP_LONG_TO_INT:
1642 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1643 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1644 storeValue(cUnit, rlDest, rlSrc[0]);
1645 break;
1646
1647 case OP_INT_TO_BYTE:
1648 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1649 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1650 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1651 storeValue(cUnit, rlDest, rlResult);
1652 break;
1653
1654 case OP_INT_TO_SHORT:
1655 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1656 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1657 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1658 storeValue(cUnit, rlDest, rlResult);
1659 break;
1660
1661 case OP_INT_TO_CHAR:
1662 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1663 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1664 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1665 storeValue(cUnit, rlDest, rlResult);
1666 break;
1667
1668 case OP_INT_TO_FLOAT:
1669 case OP_INT_TO_DOUBLE:
1670 case OP_LONG_TO_FLOAT:
1671 case OP_LONG_TO_DOUBLE:
1672 case OP_FLOAT_TO_INT:
1673 case OP_FLOAT_TO_LONG:
1674 case OP_FLOAT_TO_DOUBLE:
1675 case OP_DOUBLE_TO_INT:
1676 case OP_DOUBLE_TO_LONG:
1677 case OP_DOUBLE_TO_FLOAT:
1678 genConversion(cUnit, mir);
1679 break;
1680
1681 case OP_ADD_INT:
1682 case OP_SUB_INT:
1683 case OP_MUL_INT:
1684 case OP_DIV_INT:
1685 case OP_REM_INT:
1686 case OP_AND_INT:
1687 case OP_OR_INT:
1688 case OP_XOR_INT:
1689 case OP_SHL_INT:
1690 case OP_SHR_INT:
1691 case OP_USHR_INT:
1692 case OP_ADD_INT_2ADDR:
1693 case OP_SUB_INT_2ADDR:
1694 case OP_MUL_INT_2ADDR:
1695 case OP_DIV_INT_2ADDR:
1696 case OP_REM_INT_2ADDR:
1697 case OP_AND_INT_2ADDR:
1698 case OP_OR_INT_2ADDR:
1699 case OP_XOR_INT_2ADDR:
1700 case OP_SHL_INT_2ADDR:
1701 case OP_SHR_INT_2ADDR:
1702 case OP_USHR_INT_2ADDR:
1703 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1704 break;
1705
1706 case OP_ADD_LONG:
1707 case OP_SUB_LONG:
1708 case OP_MUL_LONG:
1709 case OP_DIV_LONG:
1710 case OP_REM_LONG:
1711 case OP_AND_LONG:
1712 case OP_OR_LONG:
1713 case OP_XOR_LONG:
1714 case OP_ADD_LONG_2ADDR:
1715 case OP_SUB_LONG_2ADDR:
1716 case OP_MUL_LONG_2ADDR:
1717 case OP_DIV_LONG_2ADDR:
1718 case OP_REM_LONG_2ADDR:
1719 case OP_AND_LONG_2ADDR:
1720 case OP_OR_LONG_2ADDR:
1721 case OP_XOR_LONG_2ADDR:
1722 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1723 break;
1724
buzbee67bf8852011-08-17 17:51:35 -07001725 case OP_SHL_LONG:
1726 case OP_SHR_LONG:
1727 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001728 case OP_SHL_LONG_2ADDR:
1729 case OP_SHR_LONG_2ADDR:
1730 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001731 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1732 break;
1733
1734 case OP_ADD_FLOAT:
1735 case OP_SUB_FLOAT:
1736 case OP_MUL_FLOAT:
1737 case OP_DIV_FLOAT:
1738 case OP_REM_FLOAT:
1739 case OP_ADD_FLOAT_2ADDR:
1740 case OP_SUB_FLOAT_2ADDR:
1741 case OP_MUL_FLOAT_2ADDR:
1742 case OP_DIV_FLOAT_2ADDR:
1743 case OP_REM_FLOAT_2ADDR:
1744 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1745 break;
1746
1747 case OP_ADD_DOUBLE:
1748 case OP_SUB_DOUBLE:
1749 case OP_MUL_DOUBLE:
1750 case OP_DIV_DOUBLE:
1751 case OP_REM_DOUBLE:
1752 case OP_ADD_DOUBLE_2ADDR:
1753 case OP_SUB_DOUBLE_2ADDR:
1754 case OP_MUL_DOUBLE_2ADDR:
1755 case OP_DIV_DOUBLE_2ADDR:
1756 case OP_REM_DOUBLE_2ADDR:
1757 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1758 break;
1759
1760 case OP_RSUB_INT:
1761 case OP_ADD_INT_LIT16:
1762 case OP_MUL_INT_LIT16:
1763 case OP_DIV_INT_LIT16:
1764 case OP_REM_INT_LIT16:
1765 case OP_AND_INT_LIT16:
1766 case OP_OR_INT_LIT16:
1767 case OP_XOR_INT_LIT16:
1768 case OP_ADD_INT_LIT8:
1769 case OP_RSUB_INT_LIT8:
1770 case OP_MUL_INT_LIT8:
1771 case OP_DIV_INT_LIT8:
1772 case OP_REM_INT_LIT8:
1773 case OP_AND_INT_LIT8:
1774 case OP_OR_INT_LIT8:
1775 case OP_XOR_INT_LIT8:
1776 case OP_SHL_INT_LIT8:
1777 case OP_SHR_INT_LIT8:
1778 case OP_USHR_INT_LIT8:
1779 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1780 break;
1781
1782 default:
1783 res = true;
1784 }
1785 return res;
1786}
1787
buzbeeed3e9302011-09-23 17:34:19 -07001788STATIC const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001789 "kMirOpPhi",
1790 "kMirOpNullNRangeUpCheck",
1791 "kMirOpNullNRangeDownCheck",
1792 "kMirOpLowerBound",
1793 "kMirOpPunt",
1794 "kMirOpCheckInlinePrediction",
1795};
1796
1797/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001798STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001799{
1800 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1801 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1802 strcpy(msg, extendedMIROpNames[opOffset]);
1803 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1804
1805 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1806 case kMirOpPhi: {
1807 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1808 op->flags.isNop = true;
1809 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1810 break;
1811 }
1812 default:
1813 break;
1814 }
1815}
1816
buzbee67bc2362011-10-11 18:08:40 -07001817/*
1818 * If there are any ins passed in registers that have not been promoted
1819 * to a callee-save register, flush them to the frame. Perform intial
1820 * assignment of promoted arguments.
1821 */
buzbeeed3e9302011-09-23 17:34:19 -07001822STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001823{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001824 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001825 return;
buzbee67bc2362011-10-11 18:08:40 -07001826 int firstArgReg = r1;
1827 int lastArgReg = r3;
1828 int startVReg = cUnit->method->NumRegisters() -
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001829 cUnit->method->NumIns();
buzbee8febc582011-10-25 12:39:20 -07001830 /*
1831 * Arguments passed in registers should be flushed
1832 * to their backing locations in the frame for now.
1833 * Also, we need to do initial assignment for promoted
1834 * arguments. NOTE: an older version of dx had an issue
1835 * in which it would reuse static method argument registers.
1836 * This could result in the same Dalvik virtual register
1837 * being promoted to both core and fp regs. In those
1838 * cases, copy argument to both. This will be uncommon
1839 * enough that it isn't worth attempting to optimize.
1840 */
buzbee67bc2362011-10-11 18:08:40 -07001841 for (int i = 0; i < cUnit->method->NumIns(); i++) {
1842 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001843 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001844 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001845 if (vMap.coreLocation == kLocPhysReg) {
1846 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001847 }
1848 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001849 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1850 }
1851 // Also put a copy in memory in case we're partially promoted
1852 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1853 firstArgReg + i, kWord);
1854 } else {
buzbee8febc582011-10-25 12:39:20 -07001855 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001856 if (vMap.coreLocation == kLocPhysReg) {
1857 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1858 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001859 }
1860 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001861 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1862 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001863 }
1864 }
buzbee67bf8852011-08-17 17:51:35 -07001865 }
1866}
1867
1868/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001869STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001870{
1871 MIR* mir;
1872 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1873 int blockId = bb->id;
1874
1875 cUnit->curBlock = bb;
1876 labelList[blockId].operands[0] = bb->startOffset;
1877
1878 /* Insert the block label */
1879 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1880 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1881
buzbee6181f792011-09-29 11:14:04 -07001882 /* Reset local optimization data on block boundaries */
1883 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001884 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001885 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001886
1887 ArmLIR* headLIR = NULL;
1888
buzbeebbaf8942011-10-02 13:08:29 -07001889 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001890 if (bb->blockType == kEntryBlock) {
1891 /*
1892 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1893 * mechanism know so it doesn't try to use any of them when
1894 * expanding the frame or flushing. This leaves the utility
1895 * code with a single temp: r12. This should be enough.
1896 */
1897 oatLockTemp(cUnit, r0);
1898 oatLockTemp(cUnit, r1);
1899 oatLockTemp(cUnit, r2);
1900 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001901
1902 /*
1903 * We can safely skip the stack overflow check if we're
1904 * a leaf *and* our frame size < fudge factor.
1905 */
1906 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1907 ((size_t)cUnit->frameSize <
1908 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001909 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001910 if (!skipOverflowCheck) {
1911 /* Load stack limit */
1912 loadWordDisp(cUnit, rSELF,
1913 art::Thread::StackEndOffset().Int32Value(), r12);
1914 }
buzbee67bf8852011-08-17 17:51:35 -07001915 /* Spill core callee saves */
1916 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1917 /* Need to spill any FP regs? */
1918 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001919 /*
1920 * NOTE: fp spills are a little different from core spills in that
1921 * they are pushed as a contiguous block. When promoting from
1922 * the fp set, we must allocate all singles from s16..highest-promoted
1923 */
buzbee67bf8852011-08-17 17:51:35 -07001924 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1925 }
buzbeecefd1872011-09-09 09:59:52 -07001926 if (!skipOverflowCheck) {
1927 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001928 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001929 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1930 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001931 genRegCopy(cUnit, rSP, rLR); // Establish stack
1932 } else {
1933 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001934 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001935 }
buzbee67bf8852011-08-17 17:51:35 -07001936 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1937 flushIns(cUnit);
1938 oatFreeTemp(cUnit, r0);
1939 oatFreeTemp(cUnit, r1);
1940 oatFreeTemp(cUnit, r2);
1941 oatFreeTemp(cUnit, r3);
1942 } else if (bb->blockType == kExitBlock) {
1943 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07001944 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07001945 /* Need to restore any FP callee saves? */
1946 if (cUnit->numFPSpills) {
1947 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1948 }
1949 if (cUnit->coreSpillMask & (1 << rLR)) {
1950 /* Unspill rLR to rPC */
1951 cUnit->coreSpillMask &= ~(1 << rLR);
1952 cUnit->coreSpillMask |= (1 << rPC);
1953 }
1954 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1955 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1956 /* We didn't pop to rPC, so must do a bv rLR */
1957 newLIR1(cUnit, kThumbBx, rLR);
1958 }
1959 }
1960
1961 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1962
1963 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07001964 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1965 oatClobberAllRegs(cUnit);
1966 }
buzbee67bf8852011-08-17 17:51:35 -07001967
1968 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1969 oatResetDefTracking(cUnit);
1970 }
1971
1972 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1973 handleExtendedMethodMIR(cUnit, mir);
1974 continue;
1975 }
1976
1977 cUnit->currentDalvikOffset = mir->offset;
1978
1979 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1980 InstructionFormat dalvikFormat =
1981 dexGetFormatFromOpcode(dalvikOpcode);
1982
1983 ArmLIR* boundaryLIR;
1984
1985 /* Mark the beginning of a Dalvik instruction for line tracking */
1986 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1987 (int) oatGetDalvikDisassembly(
1988 &mir->dalvikInsn, ""));
1989 /* Remember the first LIR for this block */
1990 if (headLIR == NULL) {
1991 headLIR = boundaryLIR;
1992 /* Set the first boundaryLIR as a scheduling barrier */
1993 headLIR->defMask = ENCODE_ALL;
1994 }
1995
1996 /* Don't generate the SSA annotation unless verbose mode is on */
1997 if (cUnit->printMe && mir->ssaRep) {
1998 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1999 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
2000 }
2001
2002 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
2003
2004 if (notHandled) {
2005 char buf[100];
2006 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
2007 mir->offset,
2008 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
2009 dalvikFormat);
2010 LOG(FATAL) << buf;
2011 }
2012 }
2013
2014 if (headLIR) {
2015 /*
2016 * Eliminate redundant loads/stores and delay stores into later
2017 * slots
2018 */
2019 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
2020 cUnit->lastLIRInsn);
2021
2022 /*
2023 * Generate an unconditional branch to the fallthrough block.
2024 */
2025 if (bb->fallThrough) {
2026 genUnconditionalBranch(cUnit,
2027 &labelList[bb->fallThrough->id]);
2028 }
2029 }
2030 return false;
2031}
2032
2033/*
2034 * Nop any unconditional branches that go to the next instruction.
2035 * Note: new redundant branches may be inserted later, and we'll
2036 * use a check in final instruction assembly to nop those out.
2037 */
2038void removeRedundantBranches(CompilationUnit* cUnit)
2039{
2040 ArmLIR* thisLIR;
2041
2042 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2043 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2044 thisLIR = NEXT_LIR(thisLIR)) {
2045
2046 /* Branch to the next instruction */
2047 if ((thisLIR->opcode == kThumbBUncond) ||
2048 (thisLIR->opcode == kThumb2BUncond)) {
2049 ArmLIR* nextLIR = thisLIR;
2050
2051 while (true) {
2052 nextLIR = NEXT_LIR(nextLIR);
2053
2054 /*
2055 * Is the branch target the next instruction?
2056 */
2057 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2058 thisLIR->flags.isNop = true;
2059 break;
2060 }
2061
2062 /*
2063 * Found real useful stuff between the branch and the target.
2064 * Need to explicitly check the lastLIRInsn here because it
2065 * might be the last real instruction.
2066 */
2067 if (!isPseudoOpcode(nextLIR->opcode) ||
2068 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2069 break;
2070 }
2071 }
2072 }
2073}
2074
buzbeeed3e9302011-09-23 17:34:19 -07002075STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002076{
2077 ArmLIR** suspendLabel =
2078 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2079 int numElems = cUnit->suspendLaunchpads.numUsed;
2080
2081 for (int i = 0; i < numElems; i++) {
2082 /* TUNING: move suspend count load into helper */
2083 ArmLIR* lab = suspendLabel[i];
2084 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2085 cUnit->currentDalvikOffset = lab->operands[1];
2086 oatAppendLIR(cUnit, (LIR *)lab);
2087 loadWordDisp(cUnit, rSELF,
2088 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2089 loadWordDisp(cUnit, rSELF,
2090 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2091 opReg(cUnit, kOpBlx, rLR);
2092 genUnconditionalBranch(cUnit, resumeLab);
2093 }
2094}
2095
buzbeeed3e9302011-09-23 17:34:19 -07002096STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002097{
2098 ArmLIR** throwLabel =
2099 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2100 int numElems = cUnit->throwLaunchpads.numUsed;
2101 int i;
2102
2103 for (i = 0; i < numElems; i++) {
2104 ArmLIR* lab = throwLabel[i];
2105 cUnit->currentDalvikOffset = lab->operands[1];
2106 oatAppendLIR(cUnit, (LIR *)lab);
2107 int funcOffset = 0;
2108 int v1 = lab->operands[2];
2109 int v2 = lab->operands[3];
2110 switch(lab->operands[0]) {
2111 case kArmThrowNullPointer:
2112 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2113 break;
2114 case kArmThrowArrayBounds:
2115 if (v2 != r0) {
2116 genRegCopy(cUnit, r0, v1);
2117 genRegCopy(cUnit, r1, v2);
2118 } else {
2119 if (v1 == r1) {
2120 genRegCopy(cUnit, r12, v1);
2121 genRegCopy(cUnit, r1, v2);
2122 genRegCopy(cUnit, r0, r12);
2123 } else {
2124 genRegCopy(cUnit, r1, v2);
2125 genRegCopy(cUnit, r0, v1);
2126 }
2127 }
2128 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2129 break;
2130 case kArmThrowDivZero:
2131 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2132 break;
2133 case kArmThrowVerificationError:
2134 loadConstant(cUnit, r0, v1);
2135 loadConstant(cUnit, r1, v2);
2136 funcOffset =
2137 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2138 break;
2139 case kArmThrowNegArraySize:
2140 genRegCopy(cUnit, r0, v1);
2141 funcOffset =
2142 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2143 break;
buzbee5ade1d22011-09-09 14:44:52 -07002144 case kArmThrowNoSuchMethod:
2145 genRegCopy(cUnit, r0, v1);
2146 funcOffset =
2147 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2148 break;
buzbeeec5adf32011-09-11 15:25:43 -07002149 case kArmThrowStackOverflow:
2150 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002151 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002152 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002153 opRegImm(cUnit, kOpAdd, rSP,
2154 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002155 break;
buzbee5ade1d22011-09-09 14:44:52 -07002156 default:
2157 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2158 }
2159 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002160 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002161 }
2162}
2163
buzbee67bf8852011-08-17 17:51:35 -07002164void oatMethodMIR2LIR(CompilationUnit* cUnit)
2165{
2166 /* Used to hold the labels of each block */
2167 cUnit->blockLabelList =
2168 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2169
2170 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2171 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002172 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002173
2174 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002175
2176 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002177}
2178
2179/* Common initialization routine for an architecture family */
2180bool oatArchInit()
2181{
2182 int i;
2183
2184 for (i = 0; i < kArmLast; i++) {
2185 if (EncodingMap[i].opcode != i) {
2186 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2187 " is wrong: expecting " << i << ", seeing " <<
2188 (int)EncodingMap[i].opcode;
2189 }
2190 }
2191
2192 return oatArchVariantInit();
2193}
2194
2195/* Needed by the Assembler */
2196void oatSetupResourceMasks(ArmLIR* lir)
2197{
2198 setupResourceMasks(lir);
2199}
2200
2201/* Needed by the ld/st optmizatons */
2202ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2203{
2204 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2205}
2206
2207/* Needed by the register allocator */
2208ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2209{
2210 return genRegCopy(cUnit, rDest, rSrc);
2211}
2212
2213/* Needed by the register allocator */
2214void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2215 int srcLo, int srcHi)
2216{
2217 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2218}
2219
2220void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2221 int displacement, int rSrc, OpSize size)
2222{
2223 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2224}
2225
2226void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2227 int displacement, int rSrcLo, int rSrcHi)
2228{
2229 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2230}