blob: 9e026bea9ffc660c540d4a7d022b68e3e0444328 [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
Elliott Hughes1240dad2011-09-09 16:24:50 -070017#define DISPLAY_MISSING_TARGETS 1
18
buzbeeed3e9302011-09-23 17:34:19 -070019STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
buzbee67bf8852011-08-17 17:51:35 -070020 INVALID_REG, INVALID_SREG, 0,
21 kLocDalvikFrame, INVALID_REG, INVALID_REG,
22 INVALID_OFFSET};
buzbee6181f792011-09-29 11:14:04 -070023
24/* Mark register usage state and return long retloc */
25STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
26{
27 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
28 oatLockTemp(cUnit, res.lowReg);
29 oatLockTemp(cUnit, res.highReg);
30 oatMarkPair(cUnit, res.lowReg, res.highReg);
31 return res;
32}
33
34STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
35{
36 RegLocation res = LOC_DALVIK_RETURN_VAL;
37 oatLockTemp(cUnit, res.lowReg);
38 return res;
39}
buzbee67bf8852011-08-17 17:51:35 -070040
buzbeedfd3d702011-08-28 12:56:51 -070041/*
42 * Let helper function take care of everything. Will call
43 * Array::AllocFromCode(type_idx, method, count);
44 * Note: AllocFromCode will handle checks for errNegativeArraySize.
45 */
buzbeeed3e9302011-09-23 17:34:19 -070046STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -070047 RegLocation rlSrc)
48{
buzbeedfd3d702011-08-28 12:56:51 -070049 oatFlushAllRegs(cUnit); /* Everything to home location */
50 loadWordDisp(cUnit, rSELF,
Ian Rogersb886da82011-09-23 16:27:54 -070051 OFFSETOF_MEMBER(Thread, pArrayAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070052 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
53 loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
54 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070055 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070056 RegLocation rlResult = oatGetReturn(cUnit);
57 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070058}
59
60/*
61 * Similar to genNewArray, but with post-allocation initialization.
62 * Verifier guarantees we're dealing with an array class. Current
63 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
64 * Current code also throws internal unimp if not 'L', '[' or 'I'.
65 */
buzbeeed3e9302011-09-23 17:34:19 -070066STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070067{
68 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070069 int elems = dInsn->vA;
70 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070071 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070072 loadWordDisp(cUnit, rSELF,
Ian Rogersb886da82011-09-23 16:27:54 -070073 OFFSETOF_MEMBER(Thread, pCheckAndArrayAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070074 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
75 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
76 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070077 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070078 /*
buzbeedfd3d702011-08-28 12:56:51 -070079 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
80 * return region. Because AllocFromCode placed the new array
81 * in r0, we'll just lock it into place. When debugger support is
82 * added, it may be necessary to additionally copy all return
83 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070084 */
buzbee67bf8852011-08-17 17:51:35 -070085 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070086
buzbee67bf8852011-08-17 17:51:35 -070087 // Having a range of 0 is legal
88 if (isRange && (dInsn->vA > 0)) {
89 /*
90 * Bit of ugliness here. We're going generate a mem copy loop
91 * on the register range, but it is possible that some regs
92 * in the range have been promoted. This is unlikely, but
93 * before generating the copy, we'll just force a flush
94 * of any regs in the source range that have been promoted to
95 * home location.
96 */
97 for (unsigned int i = 0; i < dInsn->vA; i++) {
98 RegLocation loc = oatUpdateLoc(cUnit,
99 oatGetSrc(cUnit, mir, i));
100 if (loc.location == kLocPhysReg) {
101 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
102 }
103 }
104 /*
105 * TUNING note: generated code here could be much improved, but
106 * this is an uncommon operation and isn't especially performance
107 * critical.
108 */
109 int rSrc = oatAllocTemp(cUnit);
110 int rDst = oatAllocTemp(cUnit);
111 int rIdx = oatAllocTemp(cUnit);
112 int rVal = rLR; // Using a lot of temps, rLR is known free here
113 // Set up source pointer
114 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
115 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
116 // Set up the target pointer
117 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700118 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700119 // Set up the loop counter (known to be > 0)
120 loadConstant(cUnit, rIdx, dInsn->vA);
121 // Generate the copy loop. Going backwards for convenience
122 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
123 target->defMask = ENCODE_ALL;
124 // Copy next element
125 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
126 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
127 // Use setflags encoding here
128 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
129 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
130 branch->generic.target = (LIR*)target;
131 } else if (!isRange) {
132 // TUNING: interleave
133 for (unsigned int i = 0; i < dInsn->vA; i++) {
134 RegLocation rlArg = loadValue(cUnit,
135 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700136 storeBaseDisp(cUnit, r0,
137 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700138 i * 4, rlArg.lowReg, kWord);
139 // If the loadValue caused a temp to be allocated, free it
140 if (oatIsTemp(cUnit, rlArg.lowReg)) {
141 oatFreeTemp(cUnit, rlArg.lowReg);
142 }
143 }
144 }
145}
146
Brian Carlstrom845490b2011-09-19 15:56:53 -0700147Field* FindFieldWithResolvedStaticStorage(const Method* method,
148 const uint32_t fieldIdx,
149 uint32_t& resolvedTypeIdx) {
150 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
151 Field* field = class_linker->ResolveField(fieldIdx, method, true);
152 if (field == NULL) {
153 return NULL;
154 }
155 const art::DexFile& dex_file = class_linker->
156 FindDexFile(method->GetDeclaringClass()->GetDexCache());
157 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
158 int type_idx = field_id.class_idx_;
159 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
160 // Check if storage class is the same as class referred to by type idx.
161 // They may not be if the FieldId refers a subclass, but storage is in super
162 if (field->GetDeclaringClass() == klass) {
163 resolvedTypeIdx = type_idx;
164 return field;
165 }
166 // See if we can find a dex reference for the storage class.
167 // we may not if the dex file never references the super class,
168 // but usually it will.
169 std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
170 for (size_t type_idx = 0; type_idx < dex_file.NumTypeIds(); type_idx++) {
171 const art::DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
172 if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
173 resolvedTypeIdx = type_idx;
174 return field;
175 }
176 }
177 return NULL; // resort to slow path
178}
179
buzbeeed3e9302011-09-23 17:34:19 -0700180STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700181{
buzbeee1931742011-08-28 21:15:53 -0700182 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
183 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700184 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700185 uint32_t typeIdx;
186 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700187 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700188 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700189 // Slow path
buzbee34cd9e52011-09-08 14:31:52 -0700190 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
191 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700192 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
193 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700194 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
195 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
196 loadCurrMethodDirect(cUnit, r1);
197 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700198 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700199 } else {
buzbee1da522d2011-09-04 11:22:20 -0700200 // fast path
201 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700202 // Using fixed register to sync with slow path
203 int rMethod = r1;
204 oatLockTemp(cUnit, rMethod);
205 loadCurrMethodDirect(cUnit, rMethod);
206 int rBase = r0;
207 oatLockTemp(cUnit, rBase);
208 loadWordDisp(cUnit, rMethod,
209 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
210 rBase);
211 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
212 sizeof(int32_t*)* typeIdx, rBase);
213 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700214 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700215 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
216 loadWordDisp(cUnit, rSELF,
217 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
218 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700219 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700220 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
221 skipTarget->defMask = ENCODE_ALL;
222 branchOver->generic.target = (LIR*)skipTarget;
223 rlSrc = oatGetSrc(cUnit, mir, 0);
224 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700225#if ANDROID_SMP != 0
226 if (field->IsVolatile()) {
227 oatGenMemBarrier(cUnit, kST);
228 }
229#endif
buzbee1da522d2011-09-04 11:22:20 -0700230 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700231#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700232 if (field->IsVolatile()) {
233 oatGenMemBarrier(cUnit, kSY);
234 }
buzbee67bf8852011-08-17 17:51:35 -0700235#endif
buzbee1da522d2011-09-04 11:22:20 -0700236 if (isObject) {
237 markGCCard(cUnit, rlSrc.lowReg, rBase);
238 }
239 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700240 }
buzbee67bf8852011-08-17 17:51:35 -0700241}
242
buzbeeed3e9302011-09-23 17:34:19 -0700243STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700244{
buzbee1da522d2011-09-04 11:22:20 -0700245 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700246 uint32_t typeIdx;
247 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700248 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700249#if ANDROID_SMP != 0
250 bool isVolatile = (field == NULL) || field->IsVolatile();
251#else
252 bool isVolatile = false;
253#endif
254 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
buzbee34cd9e52011-09-08 14:31:52 -0700255 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
256 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700257 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700258 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
259 loadCurrMethodDirect(cUnit, r1);
260 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700261 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700262 } else {
buzbee1da522d2011-09-04 11:22:20 -0700263 // fast path
264 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700265 // Using fixed register to sync with slow path
266 int rMethod = r1;
267 oatLockTemp(cUnit, rMethod);
268 loadCurrMethodDirect(cUnit, r1);
269 int rBase = r0;
270 oatLockTemp(cUnit, rBase);
271 loadWordDisp(cUnit, rMethod,
272 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
273 rBase);
274 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
275 sizeof(int32_t*)* typeIdx, rBase);
276 // TUNING: fast path should fall through
277 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
278 loadWordDisp(cUnit, rSELF,
279 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
280 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700281 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700282 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
283 skipTarget->defMask = ENCODE_ALL;
284 branchOver->generic.target = (LIR*)skipTarget;
285 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
286 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
287 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
288 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700289 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700290 }
buzbee67bf8852011-08-17 17:51:35 -0700291}
292
293
buzbeeed3e9302011-09-23 17:34:19 -0700294STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700295 RegLocation rlResult, RegLocation rlDest)
296{
buzbee1da522d2011-09-04 11:22:20 -0700297 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700298 uint32_t typeIdx;
299 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700300#if ANDROID_SMP != 0
301 bool isVolatile = (field == NULL) || field->IsVolatile();
302#else
303 bool isVolatile = false;
304#endif
buzbee6181f792011-09-29 11:14:04 -0700305 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700306 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
buzbee34cd9e52011-09-08 14:31:52 -0700307 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
308 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700309 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700310 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
311 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700312 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700313 RegLocation rlResult = oatGetReturnWide(cUnit);
314 storeValueWide(cUnit, rlDest, rlResult);
315 } else {
buzbee1da522d2011-09-04 11:22:20 -0700316 // Fast path
317 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700318 // Using fixed register to sync with slow path
319 int rMethod = r1;
320 oatLockTemp(cUnit, rMethod);
321 loadCurrMethodDirect(cUnit, rMethod);
322 int rBase = r0;
323 oatLockTemp(cUnit, rBase);
324 loadWordDisp(cUnit, rMethod,
325 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
326 rBase);
327 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
328 sizeof(int32_t*)* typeIdx, rBase);
329 // TUNING: fast path should fall through
330 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
331 loadWordDisp(cUnit, rSELF,
332 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
333 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700334 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700335 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
336 skipTarget->defMask = ENCODE_ALL;
337 branchOver->generic.target = (LIR*)skipTarget;
338 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
339 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700340 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
341 rlResult.highReg, INVALID_SREG);
342 oatFreeTemp(cUnit, rBase);
343 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700344 }
buzbee67bf8852011-08-17 17:51:35 -0700345}
346
buzbeeed3e9302011-09-23 17:34:19 -0700347STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700348 RegLocation rlResult, RegLocation rlDest)
349{
buzbee1da522d2011-09-04 11:22:20 -0700350 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700351 uint32_t typeIdx;
352 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700353 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
354 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700355 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700356 if (SLOW_FIELD_PATH || field == NULL) {
357 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
358 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700359 // Slow path
360 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
361 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700362 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
363 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
364 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700365 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700366 RegLocation rlResult = oatGetReturn(cUnit);
367 storeValue(cUnit, rlDest, rlResult);
368 } else {
buzbee1da522d2011-09-04 11:22:20 -0700369 // Fast path
370 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700371 // Using fixed register to sync with slow path
372 int rMethod = r1;
373 oatLockTemp(cUnit, rMethod);
374 loadCurrMethodDirect(cUnit, rMethod);
375 int rBase = r0;
376 oatLockTemp(cUnit, rBase);
377 loadWordDisp(cUnit, rMethod,
378 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
379 rBase);
380 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
381 sizeof(int32_t*)* typeIdx, rBase);
382 // TUNING: fast path should fall through
383 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
384 loadWordDisp(cUnit, rSELF,
385 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
386 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700387 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700388 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
389 skipTarget->defMask = ENCODE_ALL;
390 branchOver->generic.target = (LIR*)skipTarget;
391 rlDest = oatGetDest(cUnit, mir, 0);
392 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700393#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700394 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700395 oatGenMemBarrier(cUnit, kSY);
396 }
buzbee67bf8852011-08-17 17:51:35 -0700397#endif
buzbee1da522d2011-09-04 11:22:20 -0700398 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
399 oatFreeTemp(cUnit, rBase);
400 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700401 }
buzbee67bf8852011-08-17 17:51:35 -0700402}
403
buzbee561227c2011-09-02 15:28:19 -0700404typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
405 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700406
407/*
408 * Bit of a hack here - in leiu of a real scheduling pass,
409 * emit the next instruction in static & direct invoke sequences.
410 */
buzbeeed3e9302011-09-23 17:34:19 -0700411STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700412 DecodedInstruction* dInsn, int state,
413 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700414{
buzbee561227c2011-09-02 15:28:19 -0700415 DCHECK(rollback == NULL);
416 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700417 switch(state) {
418 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700419 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700420 break;
buzbee561227c2011-09-02 15:28:19 -0700421 case 1: // Get method->code_and_direct_methods_
422 loadWordDisp(cUnit, r0,
423 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
424 r0);
buzbee67bf8852011-08-17 17:51:35 -0700425 break;
buzbee561227c2011-09-02 15:28:19 -0700426 case 2: // Grab target method* and target code_
427 loadWordDisp(cUnit, r0,
428 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
429 loadWordDisp(cUnit, r0,
430 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700431 break;
432 default:
433 return -1;
434 }
435 return state + 1;
436}
437
buzbee67bf8852011-08-17 17:51:35 -0700438/*
439 * Bit of a hack here - in leiu of a real scheduling pass,
440 * emit the next instruction in a virtual invoke sequence.
441 * We can use rLR as a temp prior to target address loading
442 * Note also that we'll load the first argument ("this") into
443 * r1 here rather than the standard loadArgRegs.
444 */
buzbeeed3e9302011-09-23 17:34:19 -0700445STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700446 DecodedInstruction* dInsn, int state,
447 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700448{
buzbee561227c2011-09-02 15:28:19 -0700449 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700450 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700451 /*
452 * This is the fast path in which the target virtual method is
453 * fully resolved at compile time.
454 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700455 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
456 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -0700457 CHECK(baseMethod != NULL);
458 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700459 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700460 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700461 rlArg = oatGetSrc(cUnit, mir, 0);
462 loadValueDirectFixed(cUnit, rlArg, r1);
463 break;
buzbee561227c2011-09-02 15:28:19 -0700464 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700465 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700466 // get this->klass_ [use r1, set rLR]
467 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700468 break;
buzbee561227c2011-09-02 15:28:19 -0700469 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
470 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700471 break;
buzbee561227c2011-09-02 15:28:19 -0700472 case 3: // Get target method [use rLR, set r0]
473 loadWordDisp(cUnit, rLR, (target_idx * 4) +
474 art::Array::DataOffset().Int32Value(), r0);
475 break;
476 case 4: // Get the target compiled code address [uses r0, sets rLR]
477 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700478 break;
479 default:
480 return -1;
481 }
482 return state + 1;
483}
484
buzbeeed3e9302011-09-23 17:34:19 -0700485STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700486 DecodedInstruction* dInsn, int state,
487 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700488{
buzbeeed3e9302011-09-23 17:34:19 -0700489 DCHECK(rollback == NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700490 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700491 ArmLIR* skipBranch;
492 ArmLIR* skipTarget;
493 /*
494 * This handles the case in which the base method is not fully
495 * resolved at compile time. We must generate code to test
496 * for resolution a run time, bail to the slow path if not to
497 * fill in all the tables. In the latter case, we'll restart at
498 * at the beginning of the sequence.
499 */
buzbee7b1b86d2011-08-26 18:59:10 -0700500 switch(state) {
501 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700502 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700503 break;
buzbee561227c2011-09-02 15:28:19 -0700504 case 1: // Get method->dex_cache_resolved_methods_
505 loadWordDisp(cUnit, r0,
506 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700507 break;
buzbee561227c2011-09-02 15:28:19 -0700508 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
509 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
510 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700511 break;
buzbee561227c2011-09-02 15:28:19 -0700512 case 3: // Resolved?
513 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
514 // Slowest path, bail to helper, rollback and retry
515 loadWordDisp(cUnit, rSELF,
516 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
517 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700518 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700519 genUnconditionalBranch(cUnit, rollback);
520 // Resume normal slow path
521 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
522 skipTarget->defMask = ENCODE_ALL;
523 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700524 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700525 loadBaseDisp(cUnit, mir, rLR,
526 Method::GetMethodIndexOffset().Int32Value(), r0,
527 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700528 // Load "this" [set r1]
529 rlArg = oatGetSrc(cUnit, mir, 0);
530 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700531 break;
532 case 4:
533 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700534 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700535 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700536 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700537 break;
buzbee561227c2011-09-02 15:28:19 -0700538 case 5:
539 // get this->klass_->vtable_ [usr rLR, set rLR]
540 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700541 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700542 // In load shadow fold vtable_ object header size into method_index_
543 opRegImm(cUnit, kOpAdd, r0,
544 art::Array::DataOffset().Int32Value() / 4);
545 // Get target Method*
546 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
547 break;
548 case 6: // Get the target compiled code address [uses r0, sets rLR]
549 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700550 break;
551 default:
552 return -1;
553 }
554 return state + 1;
555}
556
buzbeeed3e9302011-09-23 17:34:19 -0700557STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700558 DecodedInstruction* dInsn, int callState,
559 NextCallInsn nextCallInsn, ArmLIR* rollback,
560 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700561{
buzbeec0ecd652011-09-25 18:11:54 -0700562 int nextReg = r1;
563 int nextArg = 0;
564 if (skipThis) {
565 nextReg++;
566 nextArg++;
567 }
568 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
569 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
570 rlArg = oatUpdateRawLoc(cUnit, rlArg);
571 if (rlArg.wide && (nextReg <= r2)) {
572 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
573 nextReg++;
574 nextArg++;
575 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700576 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700577 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700578 }
buzbeec0ecd652011-09-25 18:11:54 -0700579 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700580 }
581 return callState;
582}
583
buzbee4a3164f2011-09-03 11:25:10 -0700584// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700585STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700586 DecodedInstruction* dInsn, int state,
587 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700588{
buzbee67bf8852011-08-17 17:51:35 -0700589 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700590 case 0: // Load trampoline target
591 loadWordDisp(cUnit, rSELF,
592 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
593 rLR);
594 // Load r0 with method index
595 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700596 break;
buzbee67bf8852011-08-17 17:51:35 -0700597 default:
598 return -1;
599 }
600 return state + 1;
601}
602
buzbee67bf8852011-08-17 17:51:35 -0700603/*
604 * Interleave launch code for INVOKE_SUPER. See comments
605 * for nextVCallIns.
606 */
buzbeeed3e9302011-09-23 17:34:19 -0700607STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700608 DecodedInstruction* dInsn, int state,
609 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700610{
buzbee4a3164f2011-09-03 11:25:10 -0700611 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700612 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700613 /*
614 * This is the fast path in which the target virtual method is
615 * fully resolved at compile time. Note also that this path assumes
616 * that the check to verify that the target method index falls
617 * within the size of the super's vtable has been done at compile-time.
618 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700619 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
620 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700621 CHECK(baseMethod != NULL);
622 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
623 CHECK(superClass != NULL);
624 int32_t target_idx = baseMethod->GetMethodIndex();
625 CHECK(superClass->GetVTable()->GetLength() > target_idx);
626 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
627 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700628 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700629 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700630 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700631 // Load "this" [set r1]
632 rlArg = oatGetSrc(cUnit, mir, 0);
633 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700634 // Get method->declaring_class_ [use r0, set rLR]
635 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
636 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700637 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700638 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700639 break;
640 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
641 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
642 rLR);
643 break;
644 case 2: // Get ...->super_class_->vtable [u/s rLR]
645 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
646 break;
647 case 3: // Get target method [use rLR, set r0]
648 loadWordDisp(cUnit, rLR, (target_idx * 4) +
649 art::Array::DataOffset().Int32Value(), r0);
650 break;
651 case 4: // Get the target compiled code address [uses r0, sets rLR]
652 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
653 break;
buzbee67bf8852011-08-17 17:51:35 -0700654 default:
655 return -1;
656 }
buzbee4a3164f2011-09-03 11:25:10 -0700657 return state + 1;
658}
659
660/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700661STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700662 DecodedInstruction* dInsn, int state,
663 ArmLIR* rollback)
664{
buzbeeed3e9302011-09-23 17:34:19 -0700665 DCHECK(rollback == NULL);
buzbee4a3164f2011-09-03 11:25:10 -0700666 RegLocation rlArg;
667 ArmLIR* skipBranch;
668 ArmLIR* skipTarget;
669 int tReg;
670 /*
671 * This handles the case in which the base method is not fully
672 * resolved at compile time. We must generate code to test
673 * for resolution a run time, bail to the slow path if not to
674 * fill in all the tables. In the latter case, we'll restart at
675 * at the beginning of the sequence.
676 */
677 switch(state) {
678 case 0: // Get the current Method* [sets r0]
679 loadCurrMethodDirect(cUnit, r0);
680 break;
681 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
682 loadWordDisp(cUnit, r0,
683 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
684 break;
685 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
686 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
687 art::Array::DataOffset().Int32Value(), rLR);
688 break;
689 case 3: // Resolved?
690 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
691 // Slowest path, bail to helper, rollback and retry
692 loadWordDisp(cUnit, rSELF,
693 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
694 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700695 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700696 genUnconditionalBranch(cUnit, rollback);
697 // Resume normal slow path
698 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
699 skipTarget->defMask = ENCODE_ALL;
700 skipBranch->generic.target = (LIR*)skipTarget;
701 // Get base_method->method_index [usr rLR, set rLR]
702 loadBaseDisp(cUnit, mir, rLR,
703 Method::GetMethodIndexOffset().Int32Value(), rLR,
704 kUnsignedHalf, INVALID_SREG);
705 // Load "this" [set r1]
706 rlArg = oatGetSrc(cUnit, mir, 0);
707 loadValueDirectFixed(cUnit, rlArg, r1);
708 // Load curMethod->declaring_class_ [uses r0, sets r0]
709 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
710 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700711 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700712 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700713 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700714 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
715 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700716 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700717 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700718 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700719 // Range check, throw NSM on failure
720 tReg = oatAllocTemp(cUnit);
721 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
722 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700723 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
724 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700725 oatFreeTemp(cUnit, tReg);
726 }
buzbee6a0f7f52011-09-05 16:14:20 -0700727 // Adjust vtable_ base past object header
728 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700729 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700730 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700731 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700732 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700733 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
734 break;
735 default:
736 return -1;
737 }
buzbee67bf8852011-08-17 17:51:35 -0700738 return state + 1;
739}
740
741/*
742 * Load up to 5 arguments, the first three of which will be in
743 * r1 .. r3. On entry r0 contains the current method pointer,
744 * and as part of the load sequence, it must be replaced with
745 * the target method pointer. Note, this may also be called
746 * for "range" variants if the number of arguments is 5 or fewer.
747 */
buzbeeed3e9302011-09-23 17:34:19 -0700748STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700749 DecodedInstruction* dInsn, int callState,
750 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700751 NextCallInsn nextCallInsn, ArmLIR* rollback,
752 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700753{
754 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700755
756 /* If no arguments, just return */
757 if (dInsn->vA == 0)
758 return callState;
759
buzbee561227c2011-09-02 15:28:19 -0700760 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700761
buzbeec0ecd652011-09-25 18:11:54 -0700762 DCHECK_LE(dInsn->vA, 5U);
763 if (dInsn->vA > 3) {
764 uint32_t nextUse = 3;
765 //Detect special case of wide arg spanning arg3/arg4
766 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
767 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
768 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
769 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
770 rlUse2.wide) {
771 int reg;
772 // Wide spans, we need the 2nd half of uses[2].
773 rlArg = oatUpdateLocWide(cUnit, rlUse2);
774 if (rlArg.location == kLocPhysReg) {
775 reg = rlArg.highReg;
776 } else {
777 // r2 & r3 can safely be used here
778 reg = r3;
779 loadWordDisp(cUnit, rSP, rlArg.spOffset + 4, reg);
780 callState = nextCallInsn(cUnit, mir, dInsn, callState,
781 rollback);
782 }
783 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
784 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
785 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
786 nextUse++;
787 }
788 // Loop through the rest
789 while (nextUse < dInsn->vA) {
790 int lowReg;
791 int highReg;
792 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
793 rlArg = oatUpdateRawLoc(cUnit, rlArg);
794 if (rlArg.location == kLocPhysReg) {
795 lowReg = rlArg.lowReg;
796 highReg = rlArg.highReg;
797 } else {
798 lowReg = r2;
799 highReg = r3;
800 if (rlArg.wide) {
801 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
802 } else {
803 loadValueDirectFixed(cUnit, rlArg, lowReg);
804 }
805 callState = nextCallInsn(cUnit, mir, dInsn, callState,
806 rollback);
807 }
808 int outsOffset = (nextUse + 1) * 4;
809 if (rlArg.wide) {
810 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
811 nextUse += 2;
812 } else {
813 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
814 nextUse++;
815 }
buzbee561227c2011-09-02 15:28:19 -0700816 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700817 }
buzbee67bf8852011-08-17 17:51:35 -0700818 }
819
buzbeec0ecd652011-09-25 18:11:54 -0700820 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
821 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700822
buzbee6a0f7f52011-09-05 16:14:20 -0700823 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700824 // Load direct & need a "this" null check?
825 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700826 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700827 }
828 return callState;
829}
830
831/*
832 * May have 0+ arguments (also used for jumbo). Note that
833 * source virtual registers may be in physical registers, so may
834 * need to be flushed to home location before copying. This
835 * applies to arg3 and above (see below).
836 *
837 * Two general strategies:
838 * If < 20 arguments
839 * Pass args 3-18 using vldm/vstm block copy
840 * Pass arg0, arg1 & arg2 in r1-r3
841 * If 20+ arguments
842 * Pass args arg19+ using memcpy block copy
843 * Pass arg0, arg1 & arg2 in r1-r3
844 *
845 */
buzbeeed3e9302011-09-23 17:34:19 -0700846STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700847 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700848 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700849 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700850{
851 int firstArg = dInsn->vC;
852 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700853
buzbee67bf8852011-08-17 17:51:35 -0700854 // If we can treat it as non-range (Jumbo ops will use range form)
855 if (numArgs <= 5)
856 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700857 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700858 /*
859 * Make sure range list doesn't span the break between in normal
860 * Dalvik vRegs and the ins.
861 */
buzbee1b4c8592011-08-31 10:43:51 -0700862 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700863 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700864 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
865 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700866 }
867
868 /*
869 * First load the non-register arguments. Both forms expect all
870 * of the source arguments to be in their home frame location, so
871 * scan the sReg names and flush any that have been promoted to
872 * frame backing storage.
873 */
874 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700875 for (int nextArg = 0; nextArg < numArgs;) {
876 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700877 if (loc.wide) {
878 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700879 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee1b4c8592011-08-31 10:43:51 -0700880 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
881 loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700882 }
buzbeec0ecd652011-09-25 18:11:54 -0700883 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700884 } else {
885 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700886 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee1b4c8592011-08-31 10:43:51 -0700887 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700888 }
buzbeec0ecd652011-09-25 18:11:54 -0700889 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700890 }
891 }
892
893 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
894 int outsOffset = 4 /* Method* */ + (3 * 4);
895 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700896 // Generate memcpy
897 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
898 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700899 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
900 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700901 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700902 // Restore Method*
903 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700904 } else {
905 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700906 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700907 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700908 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700909 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
910 //TUNING: loosen barrier
911 ld->defMask = ENCODE_ALL;
912 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700913 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700914 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700915 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700916 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
917 setMemRefType(st, false /* isLoad */, kDalvikReg);
918 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700919 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700920 }
921
buzbeec0ecd652011-09-25 18:11:54 -0700922 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
923 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700924
buzbee561227c2011-09-02 15:28:19 -0700925 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700926 return callState;
927}
928
buzbee2a475e72011-09-07 17:19:17 -0700929#ifdef DISPLAY_MISSING_TARGETS
930// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700931STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700932{
933 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
934 loadWordDisp(cUnit, rSELF,
935 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
936 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
937 target->defMask = -1;
938 branchOver->generic.target = (LIR*)target;
939}
940#endif
941
buzbeeed3e9302011-09-23 17:34:19 -0700942STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700943 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700944{
945 DecodedInstruction* dInsn = &mir->dalvikInsn;
946 int callState = 0;
947 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700948 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700949 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700950 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700951
buzbee109bd6a2011-09-06 13:58:41 -0700952 // Explicit register usage
953 oatLockCallTemps(cUnit);
954
buzbee561227c2011-09-02 15:28:19 -0700955 if (range) {
956 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700957 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700958 } else {
959 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700960 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700961 }
buzbee67bf8852011-08-17 17:51:35 -0700962 // Finish up any of the call sequence not interleaved in arg loading
963 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700964 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700965 }
buzbee2a475e72011-09-07 17:19:17 -0700966#ifdef DISPLAY_MISSING_TARGETS
967 genShowTarget(cUnit);
968#endif
buzbeeec5adf32011-09-11 15:25:43 -0700969 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700970 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700971}
972
buzbee4a3164f2011-09-03 11:25:10 -0700973/*
974 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
975 * which will locate the target and continue on via a tail call.
976 */
buzbeeed3e9302011-09-23 17:34:19 -0700977STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -0700978{
979 DecodedInstruction* dInsn = &mir->dalvikInsn;
980 int callState = 0;
981 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -0700982 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -0700983
984 // Explicit register usage
985 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700986 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700987 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700988 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
989 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700990 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -0700991 false);
buzbee67bf8852011-08-17 17:51:35 -0700992 else
993 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -0700994 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -0700995 // Finish up any of the call sequence not interleaved in arg loading
996 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700997 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700998 }
buzbee2a475e72011-09-07 17:19:17 -0700999#ifdef DISPLAY_MISSING_TARGETS
1000 genShowTarget(cUnit);
1001#endif
buzbeeec5adf32011-09-11 15:25:43 -07001002 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001003 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001004}
1005
buzbeeed3e9302011-09-23 17:34:19 -07001006STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001007{
1008 DecodedInstruction* dInsn = &mir->dalvikInsn;
1009 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001010 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001011 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1012 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -07001013 NextCallInsn nextCallInsn;
1014 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001015 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001016
1017 // Explicit register usage
1018 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001019 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -07001020 fastPath = false;
1021 } else {
1022 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
1023 if (superClass == NULL) {
1024 fastPath = false;
1025 } else {
1026 int32_t target_idx = baseMethod->GetMethodIndex();
1027 if (superClass->GetVTable()->GetLength() <= target_idx) {
1028 fastPath = false;
1029 } else {
1030 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1031 }
1032 }
1033 }
1034 if (fastPath) {
1035 nextCallInsn = nextSuperCallInsn;
1036 rollback = NULL;
1037 } else {
1038 nextCallInsn = nextSuperCallInsnSP;
1039 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1040 rollback->defMask = -1;
1041 }
buzbee67bf8852011-08-17 17:51:35 -07001042 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001043 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001044 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001045 else
buzbeec0ecd652011-09-25 18:11:54 -07001046 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001047 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001048 // Finish up any of the call sequence not interleaved in arg loading
1049 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001050 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001051 }
buzbee2a475e72011-09-07 17:19:17 -07001052#ifdef DISPLAY_MISSING_TARGETS
1053 genShowTarget(cUnit);
1054#endif
buzbeeec5adf32011-09-11 15:25:43 -07001055 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001056 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001057}
1058
buzbeeed3e9302011-09-23 17:34:19 -07001059STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001060{
1061 DecodedInstruction* dInsn = &mir->dalvikInsn;
1062 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001063 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001064 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1065 Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -07001066 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001067 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee7b1b86d2011-08-26 18:59:10 -07001068
buzbee109bd6a2011-09-06 13:58:41 -07001069 // Explicit register usage
1070 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001071 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001072 // Slow path
1073 nextCallInsn = nextVCallInsnSP;
1074 // If we need a slow-path callout, we'll restart here
1075 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1076 rollback->defMask = -1;
1077 } else {
1078 // Fast path
1079 nextCallInsn = nextVCallInsn;
1080 rollback = NULL;
1081 }
buzbee67bf8852011-08-17 17:51:35 -07001082 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001083 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001084 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001085 else
buzbeec0ecd652011-09-25 18:11:54 -07001086 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001087 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001088 // Finish up any of the call sequence not interleaved in arg loading
1089 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001090 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001091 }
buzbee2a475e72011-09-07 17:19:17 -07001092#ifdef DISPLAY_MISSING_TARGETS
1093 genShowTarget(cUnit);
1094#endif
buzbeeec5adf32011-09-11 15:25:43 -07001095 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001096 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001097}
1098
buzbeeed3e9302011-09-23 17:34:19 -07001099STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001100 BasicBlock* bb, ArmLIR* labelList)
1101{
1102 bool res = false; // Assume success
1103 RegLocation rlSrc[3];
1104 RegLocation rlDest = badLoc;
1105 RegLocation rlResult = badLoc;
1106 Opcode opcode = mir->dalvikInsn.opcode;
1107
1108 /* Prep Src and Dest locations */
1109 int nextSreg = 0;
1110 int nextLoc = 0;
1111 int attrs = oatDataFlowAttributes[opcode];
1112 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1113 if (attrs & DF_UA) {
1114 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1115 nextSreg++;
1116 } else if (attrs & DF_UA_WIDE) {
1117 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1118 nextSreg + 1);
1119 nextSreg+= 2;
1120 }
1121 if (attrs & DF_UB) {
1122 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1123 nextSreg++;
1124 } else if (attrs & DF_UB_WIDE) {
1125 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1126 nextSreg + 1);
1127 nextSreg+= 2;
1128 }
1129 if (attrs & DF_UC) {
1130 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1131 } else if (attrs & DF_UC_WIDE) {
1132 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1133 nextSreg + 1);
1134 }
1135 if (attrs & DF_DA) {
1136 rlDest = oatGetDest(cUnit, mir, 0);
1137 } else if (attrs & DF_DA_WIDE) {
1138 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1139 }
1140
1141 switch(opcode) {
1142 case OP_NOP:
1143 break;
1144
1145 case OP_MOVE_EXCEPTION:
1146 int exOffset;
1147 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001148 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001149 resetReg = oatAllocTemp(cUnit);
1150 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1151 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1152 loadConstant(cUnit, resetReg, 0);
1153 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1154 storeValue(cUnit, rlDest, rlResult);
1155 break;
1156
1157 case OP_RETURN_VOID:
buzbeec0ecd652011-09-25 18:11:54 -07001158 genSuspendPoll(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001159 break;
1160
1161 case OP_RETURN:
1162 case OP_RETURN_OBJECT:
buzbeec1f45042011-09-21 16:03:19 -07001163 genSuspendPoll(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001164 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001165 break;
1166
1167 case OP_RETURN_WIDE:
buzbeec1f45042011-09-21 16:03:19 -07001168 genSuspendPoll(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001169 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001170 break;
1171
1172 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001173 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001174 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001175 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001176 break;
1177
1178 case OP_MOVE_RESULT:
1179 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001180 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001181 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001182 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001183 break;
1184
1185 case OP_MOVE:
1186 case OP_MOVE_OBJECT:
1187 case OP_MOVE_16:
1188 case OP_MOVE_OBJECT_16:
1189 case OP_MOVE_FROM16:
1190 case OP_MOVE_OBJECT_FROM16:
1191 storeValue(cUnit, rlDest, rlSrc[0]);
1192 break;
1193
1194 case OP_MOVE_WIDE:
1195 case OP_MOVE_WIDE_16:
1196 case OP_MOVE_WIDE_FROM16:
1197 storeValueWide(cUnit, rlDest, rlSrc[0]);
1198 break;
1199
1200 case OP_CONST:
1201 case OP_CONST_4:
1202 case OP_CONST_16:
1203 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1204 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1205 storeValue(cUnit, rlDest, rlResult);
1206 break;
1207
1208 case OP_CONST_HIGH16:
1209 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1210 loadConstantNoClobber(cUnit, rlResult.lowReg,
1211 mir->dalvikInsn.vB << 16);
1212 storeValue(cUnit, rlDest, rlResult);
1213 break;
1214
1215 case OP_CONST_WIDE_16:
1216 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001217 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1218 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1219 mir->dalvikInsn.vB,
1220 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001221 storeValueWide(cUnit, rlDest, rlResult);
1222 break;
1223
1224 case OP_CONST_WIDE:
1225 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1226 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001227 mir->dalvikInsn.vB_wide & 0xffffffff,
1228 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001229 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001230 break;
1231
1232 case OP_CONST_WIDE_HIGH16:
1233 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1234 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1235 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001236 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001237 break;
1238
1239 case OP_MONITOR_ENTER:
1240 genMonitorEnter(cUnit, mir, rlSrc[0]);
1241 break;
1242
1243 case OP_MONITOR_EXIT:
1244 genMonitorExit(cUnit, mir, rlSrc[0]);
1245 break;
1246
1247 case OP_CHECK_CAST:
1248 genCheckCast(cUnit, mir, rlSrc[0]);
1249 break;
1250
1251 case OP_INSTANCE_OF:
1252 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1253 break;
1254
1255 case OP_NEW_INSTANCE:
1256 genNewInstance(cUnit, mir, rlDest);
1257 break;
1258
1259 case OP_THROW:
1260 genThrow(cUnit, mir, rlSrc[0]);
1261 break;
1262
buzbee5ade1d22011-09-09 14:44:52 -07001263 case OP_THROW_VERIFICATION_ERROR:
1264 loadWordDisp(cUnit, rSELF,
1265 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1266 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1267 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001268 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001269 break;
1270
buzbee67bf8852011-08-17 17:51:35 -07001271 case OP_ARRAY_LENGTH:
1272 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001273 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001274 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001275 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001276 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1277 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1278 rlResult.lowReg);
1279 storeValue(cUnit, rlDest, rlResult);
1280 break;
1281
1282 case OP_CONST_STRING:
1283 case OP_CONST_STRING_JUMBO:
1284 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1285 break;
1286
1287 case OP_CONST_CLASS:
1288 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1289 break;
1290
1291 case OP_FILL_ARRAY_DATA:
1292 genFillArrayData(cUnit, mir, rlSrc[0]);
1293 break;
1294
1295 case OP_FILLED_NEW_ARRAY:
1296 genFilledNewArray(cUnit, mir, false /* not range */);
1297 break;
1298
1299 case OP_FILLED_NEW_ARRAY_RANGE:
1300 genFilledNewArray(cUnit, mir, true /* range */);
1301 break;
1302
1303 case OP_NEW_ARRAY:
1304 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1305 break;
1306
1307 case OP_GOTO:
1308 case OP_GOTO_16:
1309 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001310 if (bb->taken->startOffset <= mir->offset) {
1311 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001312 }
1313 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1314 break;
1315
1316 case OP_PACKED_SWITCH:
1317 genPackedSwitch(cUnit, mir, rlSrc[0]);
1318 break;
1319
1320 case OP_SPARSE_SWITCH:
1321 genSparseSwitch(cUnit, mir, rlSrc[0]);
1322 break;
1323
1324 case OP_CMPL_FLOAT:
1325 case OP_CMPG_FLOAT:
1326 case OP_CMPL_DOUBLE:
1327 case OP_CMPG_DOUBLE:
1328 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1329 break;
1330
1331 case OP_CMP_LONG:
1332 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1333 break;
1334
1335 case OP_IF_EQ:
1336 case OP_IF_NE:
1337 case OP_IF_LT:
1338 case OP_IF_GE:
1339 case OP_IF_GT:
1340 case OP_IF_LE: {
1341 bool backwardBranch;
1342 ArmConditionCode cond;
1343 backwardBranch = (bb->taken->startOffset <= mir->offset);
1344 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001345 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001346 }
1347 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1348 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1349 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1350 switch(opcode) {
1351 case OP_IF_EQ:
1352 cond = kArmCondEq;
1353 break;
1354 case OP_IF_NE:
1355 cond = kArmCondNe;
1356 break;
1357 case OP_IF_LT:
1358 cond = kArmCondLt;
1359 break;
1360 case OP_IF_GE:
1361 cond = kArmCondGe;
1362 break;
1363 case OP_IF_GT:
1364 cond = kArmCondGt;
1365 break;
1366 case OP_IF_LE:
1367 cond = kArmCondLe;
1368 break;
1369 default:
1370 cond = (ArmConditionCode)0;
1371 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1372 }
1373 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1374 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1375 break;
1376 }
1377
1378 case OP_IF_EQZ:
1379 case OP_IF_NEZ:
1380 case OP_IF_LTZ:
1381 case OP_IF_GEZ:
1382 case OP_IF_GTZ:
1383 case OP_IF_LEZ: {
1384 bool backwardBranch;
1385 ArmConditionCode cond;
1386 backwardBranch = (bb->taken->startOffset <= mir->offset);
1387 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001388 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001389 }
1390 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1391 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1392 switch(opcode) {
1393 case OP_IF_EQZ:
1394 cond = kArmCondEq;
1395 break;
1396 case OP_IF_NEZ:
1397 cond = kArmCondNe;
1398 break;
1399 case OP_IF_LTZ:
1400 cond = kArmCondLt;
1401 break;
1402 case OP_IF_GEZ:
1403 cond = kArmCondGe;
1404 break;
1405 case OP_IF_GTZ:
1406 cond = kArmCondGt;
1407 break;
1408 case OP_IF_LEZ:
1409 cond = kArmCondLe;
1410 break;
1411 default:
1412 cond = (ArmConditionCode)0;
1413 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1414 }
1415 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1416 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1417 break;
1418 }
1419
1420 case OP_AGET_WIDE:
1421 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1422 break;
1423 case OP_AGET:
1424 case OP_AGET_OBJECT:
1425 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1426 break;
1427 case OP_AGET_BOOLEAN:
1428 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1429 rlDest, 0);
1430 break;
1431 case OP_AGET_BYTE:
1432 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1433 break;
1434 case OP_AGET_CHAR:
1435 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1436 rlDest, 1);
1437 break;
1438 case OP_AGET_SHORT:
1439 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1440 break;
1441 case OP_APUT_WIDE:
1442 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1443 break;
1444 case OP_APUT:
1445 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1446 break;
1447 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001448 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001449 break;
1450 case OP_APUT_SHORT:
1451 case OP_APUT_CHAR:
1452 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1453 rlSrc[0], 1);
1454 break;
1455 case OP_APUT_BYTE:
1456 case OP_APUT_BOOLEAN:
1457 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1458 rlSrc[0], 0);
1459 break;
1460
1461 case OP_IGET_WIDE:
1462 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001463 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001464 break;
1465
1466 case OP_IGET:
1467 case OP_IGET_VOLATILE:
1468 case OP_IGET_OBJECT:
1469 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001470 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001471 break;
1472
1473 case OP_IGET_BOOLEAN:
1474 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001475 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001476 break;
1477
1478 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001479 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001480 break;
1481
1482 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001483 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001484 break;
1485
1486 case OP_IPUT_WIDE:
1487 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001488 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001489 break;
1490
1491 case OP_IPUT_OBJECT:
1492 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001493 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001494 break;
1495
1496 case OP_IPUT:
1497 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001498 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001499 break;
1500
1501 case OP_IPUT_BOOLEAN:
1502 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001503 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001504 break;
1505
1506 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001507 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001508 break;
1509
1510 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001511 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001512 break;
1513
1514 case OP_SGET:
1515 case OP_SGET_OBJECT:
1516 case OP_SGET_BOOLEAN:
1517 case OP_SGET_BYTE:
1518 case OP_SGET_CHAR:
1519 case OP_SGET_SHORT:
1520 genSget(cUnit, mir, rlResult, rlDest);
1521 break;
1522
1523 case OP_SGET_WIDE:
1524 genSgetWide(cUnit, mir, rlResult, rlDest);
1525 break;
1526
1527 case OP_SPUT:
1528 case OP_SPUT_OBJECT:
1529 case OP_SPUT_BOOLEAN:
1530 case OP_SPUT_BYTE:
1531 case OP_SPUT_CHAR:
1532 case OP_SPUT_SHORT:
1533 genSput(cUnit, mir, rlSrc[0]);
1534 break;
1535
1536 case OP_SPUT_WIDE:
1537 genSputWide(cUnit, mir, rlSrc[0]);
1538 break;
1539
1540 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001541 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1542 true /*range*/);
1543 break;
buzbee67bf8852011-08-17 17:51:35 -07001544 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001545 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1546 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001547 break;
1548
1549 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001550 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1551 false /*range*/);
1552 break;
buzbee67bf8852011-08-17 17:51:35 -07001553 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001554 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1555 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001556 break;
1557
1558 case OP_INVOKE_VIRTUAL:
1559 case OP_INVOKE_VIRTUAL_RANGE:
1560 genInvokeVirtual(cUnit, mir);
1561 break;
1562
1563 case OP_INVOKE_SUPER:
1564 case OP_INVOKE_SUPER_RANGE:
1565 genInvokeSuper(cUnit, mir);
1566 break;
1567
1568 case OP_INVOKE_INTERFACE:
1569 case OP_INVOKE_INTERFACE_RANGE:
1570 genInvokeInterface(cUnit, mir);
1571 break;
1572
1573 case OP_NEG_INT:
1574 case OP_NOT_INT:
1575 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1576 break;
1577
1578 case OP_NEG_LONG:
1579 case OP_NOT_LONG:
1580 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1581 break;
1582
1583 case OP_NEG_FLOAT:
1584 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1585 break;
1586
1587 case OP_NEG_DOUBLE:
1588 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1589 break;
1590
1591 case OP_INT_TO_LONG:
1592 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1593 if (rlSrc[0].location == kLocPhysReg) {
1594 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1595 } else {
1596 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1597 }
1598 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1599 rlResult.lowReg, 31);
1600 storeValueWide(cUnit, rlDest, rlResult);
1601 break;
1602
1603 case OP_LONG_TO_INT:
1604 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1605 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1606 storeValue(cUnit, rlDest, rlSrc[0]);
1607 break;
1608
1609 case OP_INT_TO_BYTE:
1610 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1611 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1612 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1613 storeValue(cUnit, rlDest, rlResult);
1614 break;
1615
1616 case OP_INT_TO_SHORT:
1617 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1618 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1619 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1620 storeValue(cUnit, rlDest, rlResult);
1621 break;
1622
1623 case OP_INT_TO_CHAR:
1624 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1625 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1626 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1627 storeValue(cUnit, rlDest, rlResult);
1628 break;
1629
1630 case OP_INT_TO_FLOAT:
1631 case OP_INT_TO_DOUBLE:
1632 case OP_LONG_TO_FLOAT:
1633 case OP_LONG_TO_DOUBLE:
1634 case OP_FLOAT_TO_INT:
1635 case OP_FLOAT_TO_LONG:
1636 case OP_FLOAT_TO_DOUBLE:
1637 case OP_DOUBLE_TO_INT:
1638 case OP_DOUBLE_TO_LONG:
1639 case OP_DOUBLE_TO_FLOAT:
1640 genConversion(cUnit, mir);
1641 break;
1642
1643 case OP_ADD_INT:
1644 case OP_SUB_INT:
1645 case OP_MUL_INT:
1646 case OP_DIV_INT:
1647 case OP_REM_INT:
1648 case OP_AND_INT:
1649 case OP_OR_INT:
1650 case OP_XOR_INT:
1651 case OP_SHL_INT:
1652 case OP_SHR_INT:
1653 case OP_USHR_INT:
1654 case OP_ADD_INT_2ADDR:
1655 case OP_SUB_INT_2ADDR:
1656 case OP_MUL_INT_2ADDR:
1657 case OP_DIV_INT_2ADDR:
1658 case OP_REM_INT_2ADDR:
1659 case OP_AND_INT_2ADDR:
1660 case OP_OR_INT_2ADDR:
1661 case OP_XOR_INT_2ADDR:
1662 case OP_SHL_INT_2ADDR:
1663 case OP_SHR_INT_2ADDR:
1664 case OP_USHR_INT_2ADDR:
1665 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1666 break;
1667
1668 case OP_ADD_LONG:
1669 case OP_SUB_LONG:
1670 case OP_MUL_LONG:
1671 case OP_DIV_LONG:
1672 case OP_REM_LONG:
1673 case OP_AND_LONG:
1674 case OP_OR_LONG:
1675 case OP_XOR_LONG:
1676 case OP_ADD_LONG_2ADDR:
1677 case OP_SUB_LONG_2ADDR:
1678 case OP_MUL_LONG_2ADDR:
1679 case OP_DIV_LONG_2ADDR:
1680 case OP_REM_LONG_2ADDR:
1681 case OP_AND_LONG_2ADDR:
1682 case OP_OR_LONG_2ADDR:
1683 case OP_XOR_LONG_2ADDR:
1684 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1685 break;
1686
buzbee67bf8852011-08-17 17:51:35 -07001687 case OP_SHL_LONG:
1688 case OP_SHR_LONG:
1689 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001690 case OP_SHL_LONG_2ADDR:
1691 case OP_SHR_LONG_2ADDR:
1692 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001693 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1694 break;
1695
1696 case OP_ADD_FLOAT:
1697 case OP_SUB_FLOAT:
1698 case OP_MUL_FLOAT:
1699 case OP_DIV_FLOAT:
1700 case OP_REM_FLOAT:
1701 case OP_ADD_FLOAT_2ADDR:
1702 case OP_SUB_FLOAT_2ADDR:
1703 case OP_MUL_FLOAT_2ADDR:
1704 case OP_DIV_FLOAT_2ADDR:
1705 case OP_REM_FLOAT_2ADDR:
1706 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1707 break;
1708
1709 case OP_ADD_DOUBLE:
1710 case OP_SUB_DOUBLE:
1711 case OP_MUL_DOUBLE:
1712 case OP_DIV_DOUBLE:
1713 case OP_REM_DOUBLE:
1714 case OP_ADD_DOUBLE_2ADDR:
1715 case OP_SUB_DOUBLE_2ADDR:
1716 case OP_MUL_DOUBLE_2ADDR:
1717 case OP_DIV_DOUBLE_2ADDR:
1718 case OP_REM_DOUBLE_2ADDR:
1719 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1720 break;
1721
1722 case OP_RSUB_INT:
1723 case OP_ADD_INT_LIT16:
1724 case OP_MUL_INT_LIT16:
1725 case OP_DIV_INT_LIT16:
1726 case OP_REM_INT_LIT16:
1727 case OP_AND_INT_LIT16:
1728 case OP_OR_INT_LIT16:
1729 case OP_XOR_INT_LIT16:
1730 case OP_ADD_INT_LIT8:
1731 case OP_RSUB_INT_LIT8:
1732 case OP_MUL_INT_LIT8:
1733 case OP_DIV_INT_LIT8:
1734 case OP_REM_INT_LIT8:
1735 case OP_AND_INT_LIT8:
1736 case OP_OR_INT_LIT8:
1737 case OP_XOR_INT_LIT8:
1738 case OP_SHL_INT_LIT8:
1739 case OP_SHR_INT_LIT8:
1740 case OP_USHR_INT_LIT8:
1741 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1742 break;
1743
1744 default:
1745 res = true;
1746 }
1747 return res;
1748}
1749
buzbeeed3e9302011-09-23 17:34:19 -07001750STATIC const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001751 "kMirOpPhi",
1752 "kMirOpNullNRangeUpCheck",
1753 "kMirOpNullNRangeDownCheck",
1754 "kMirOpLowerBound",
1755 "kMirOpPunt",
1756 "kMirOpCheckInlinePrediction",
1757};
1758
1759/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001760STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001761{
1762 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1763 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1764 strcpy(msg, extendedMIROpNames[opOffset]);
1765 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1766
1767 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1768 case kMirOpPhi: {
1769 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1770 op->flags.isNop = true;
1771 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1772 break;
1773 }
1774 default:
1775 break;
1776 }
1777}
1778
1779/* If there are any ins passed in registers that have not been promoted
1780 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001781 * Note: at this pointCopy any ins that are passed in register to their
1782 * home location */
buzbeeed3e9302011-09-23 17:34:19 -07001783STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001784{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001785 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001786 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001787 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1788 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001789 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001790 int startLoc = cUnit->method->NumRegisters() -
1791 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001792 for (int i = 0; i < inRegs; i++) {
1793 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001794 //TUNING: be smarter about flushing ins to frame
1795 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001796 if (loc.location == kLocPhysReg) {
1797 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001798 }
1799 }
1800
1801 // Handle special case of wide argument half in regs, half in frame
1802 if (inRegs == 3) {
1803 RegLocation loc = cUnit->regLocation[startLoc + 2];
1804 if (loc.wide && loc.location == kLocPhysReg) {
1805 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001806 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001807 inRegs++;
1808 }
1809 }
1810
1811 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001812 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001813 RegLocation loc = cUnit->regLocation[startLoc + i];
1814 if (loc.fpLocation == kLocPhysReg) {
1815 loc.location = kLocPhysReg;
1816 loc.fp = true;
1817 loc.lowReg = loc.fpLowReg;
1818 loc.highReg = loc.fpHighReg;
1819 }
1820 if (loc.location == kLocPhysReg) {
1821 if (loc.wide) {
buzbeeb29e4d12011-09-26 15:05:48 -07001822 if (loc.fp && (loc.lowReg & 1) != 0) {
1823 // Misaligned - need to load as a pair of singles
1824 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
1825 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
1826 } else {
1827 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1828 loc.lowReg, loc.highReg, INVALID_SREG);
1829 }
buzbee67bf8852011-08-17 17:51:35 -07001830 i++;
1831 } else {
buzbee561227c2011-09-02 15:28:19 -07001832 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001833 }
1834 }
1835 i++;
1836 }
1837}
1838
1839/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001840STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001841{
1842 MIR* mir;
1843 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1844 int blockId = bb->id;
1845
1846 cUnit->curBlock = bb;
1847 labelList[blockId].operands[0] = bb->startOffset;
1848
1849 /* Insert the block label */
1850 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1851 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1852
buzbee6181f792011-09-29 11:14:04 -07001853 /* Reset local optimization data on block boundaries */
1854 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001855 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001856 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001857
1858 ArmLIR* headLIR = NULL;
1859
1860 if (bb->blockType == kEntryBlock) {
1861 /*
1862 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1863 * mechanism know so it doesn't try to use any of them when
1864 * expanding the frame or flushing. This leaves the utility
1865 * code with a single temp: r12. This should be enough.
1866 */
1867 oatLockTemp(cUnit, r0);
1868 oatLockTemp(cUnit, r1);
1869 oatLockTemp(cUnit, r2);
1870 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001871
1872 /*
1873 * We can safely skip the stack overflow check if we're
1874 * a leaf *and* our frame size < fudge factor.
1875 */
1876 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1877 ((size_t)cUnit->frameSize <
1878 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001879 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001880 if (!skipOverflowCheck) {
1881 /* Load stack limit */
1882 loadWordDisp(cUnit, rSELF,
1883 art::Thread::StackEndOffset().Int32Value(), r12);
1884 }
buzbee67bf8852011-08-17 17:51:35 -07001885 /* Spill core callee saves */
1886 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1887 /* Need to spill any FP regs? */
1888 if (cUnit->numFPSpills) {
1889 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1890 }
buzbeecefd1872011-09-09 09:59:52 -07001891 if (!skipOverflowCheck) {
1892 opRegRegImm(cUnit, kOpSub, rLR, rSP,
1893 cUnit->frameSize - (cUnit->numSpills * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001894 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1895 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001896 genRegCopy(cUnit, rSP, rLR); // Establish stack
1897 } else {
1898 opRegImm(cUnit, kOpSub, rSP,
1899 cUnit->frameSize - (cUnit->numSpills * 4));
1900 }
buzbee67bf8852011-08-17 17:51:35 -07001901 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1902 flushIns(cUnit);
1903 oatFreeTemp(cUnit, r0);
1904 oatFreeTemp(cUnit, r1);
1905 oatFreeTemp(cUnit, r2);
1906 oatFreeTemp(cUnit, r3);
1907 } else if (bb->blockType == kExitBlock) {
1908 newLIR0(cUnit, kArmPseudoMethodExit);
1909 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1910 /* Need to restore any FP callee saves? */
1911 if (cUnit->numFPSpills) {
1912 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1913 }
1914 if (cUnit->coreSpillMask & (1 << rLR)) {
1915 /* Unspill rLR to rPC */
1916 cUnit->coreSpillMask &= ~(1 << rLR);
1917 cUnit->coreSpillMask |= (1 << rPC);
1918 }
1919 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1920 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1921 /* We didn't pop to rPC, so must do a bv rLR */
1922 newLIR1(cUnit, kThumbBx, rLR);
1923 }
1924 }
1925
1926 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1927
1928 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07001929 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1930 oatClobberAllRegs(cUnit);
1931 }
buzbee67bf8852011-08-17 17:51:35 -07001932
1933 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1934 oatResetDefTracking(cUnit);
1935 }
1936
1937 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1938 handleExtendedMethodMIR(cUnit, mir);
1939 continue;
1940 }
1941
1942 cUnit->currentDalvikOffset = mir->offset;
1943
1944 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1945 InstructionFormat dalvikFormat =
1946 dexGetFormatFromOpcode(dalvikOpcode);
1947
1948 ArmLIR* boundaryLIR;
1949
1950 /* Mark the beginning of a Dalvik instruction for line tracking */
1951 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1952 (int) oatGetDalvikDisassembly(
1953 &mir->dalvikInsn, ""));
1954 /* Remember the first LIR for this block */
1955 if (headLIR == NULL) {
1956 headLIR = boundaryLIR;
1957 /* Set the first boundaryLIR as a scheduling barrier */
1958 headLIR->defMask = ENCODE_ALL;
1959 }
1960
1961 /* Don't generate the SSA annotation unless verbose mode is on */
1962 if (cUnit->printMe && mir->ssaRep) {
1963 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1964 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1965 }
1966
1967 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1968
1969 if (notHandled) {
1970 char buf[100];
1971 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1972 mir->offset,
1973 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1974 dalvikFormat);
1975 LOG(FATAL) << buf;
1976 }
1977 }
1978
1979 if (headLIR) {
1980 /*
1981 * Eliminate redundant loads/stores and delay stores into later
1982 * slots
1983 */
1984 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1985 cUnit->lastLIRInsn);
1986
1987 /*
1988 * Generate an unconditional branch to the fallthrough block.
1989 */
1990 if (bb->fallThrough) {
1991 genUnconditionalBranch(cUnit,
1992 &labelList[bb->fallThrough->id]);
1993 }
1994 }
1995 return false;
1996}
1997
1998/*
1999 * Nop any unconditional branches that go to the next instruction.
2000 * Note: new redundant branches may be inserted later, and we'll
2001 * use a check in final instruction assembly to nop those out.
2002 */
2003void removeRedundantBranches(CompilationUnit* cUnit)
2004{
2005 ArmLIR* thisLIR;
2006
2007 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2008 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2009 thisLIR = NEXT_LIR(thisLIR)) {
2010
2011 /* Branch to the next instruction */
2012 if ((thisLIR->opcode == kThumbBUncond) ||
2013 (thisLIR->opcode == kThumb2BUncond)) {
2014 ArmLIR* nextLIR = thisLIR;
2015
2016 while (true) {
2017 nextLIR = NEXT_LIR(nextLIR);
2018
2019 /*
2020 * Is the branch target the next instruction?
2021 */
2022 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2023 thisLIR->flags.isNop = true;
2024 break;
2025 }
2026
2027 /*
2028 * Found real useful stuff between the branch and the target.
2029 * Need to explicitly check the lastLIRInsn here because it
2030 * might be the last real instruction.
2031 */
2032 if (!isPseudoOpcode(nextLIR->opcode) ||
2033 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2034 break;
2035 }
2036 }
2037 }
2038}
2039
buzbeeed3e9302011-09-23 17:34:19 -07002040STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002041{
2042 ArmLIR** suspendLabel =
2043 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2044 int numElems = cUnit->suspendLaunchpads.numUsed;
2045
2046 for (int i = 0; i < numElems; i++) {
2047 /* TUNING: move suspend count load into helper */
2048 ArmLIR* lab = suspendLabel[i];
2049 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2050 cUnit->currentDalvikOffset = lab->operands[1];
2051 oatAppendLIR(cUnit, (LIR *)lab);
2052 loadWordDisp(cUnit, rSELF,
2053 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2054 loadWordDisp(cUnit, rSELF,
2055 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2056 opReg(cUnit, kOpBlx, rLR);
2057 genUnconditionalBranch(cUnit, resumeLab);
2058 }
2059}
2060
buzbeeed3e9302011-09-23 17:34:19 -07002061STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002062{
2063 ArmLIR** throwLabel =
2064 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2065 int numElems = cUnit->throwLaunchpads.numUsed;
2066 int i;
2067
2068 for (i = 0; i < numElems; i++) {
2069 ArmLIR* lab = throwLabel[i];
2070 cUnit->currentDalvikOffset = lab->operands[1];
2071 oatAppendLIR(cUnit, (LIR *)lab);
2072 int funcOffset = 0;
2073 int v1 = lab->operands[2];
2074 int v2 = lab->operands[3];
2075 switch(lab->operands[0]) {
2076 case kArmThrowNullPointer:
2077 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2078 break;
2079 case kArmThrowArrayBounds:
2080 if (v2 != r0) {
2081 genRegCopy(cUnit, r0, v1);
2082 genRegCopy(cUnit, r1, v2);
2083 } else {
2084 if (v1 == r1) {
2085 genRegCopy(cUnit, r12, v1);
2086 genRegCopy(cUnit, r1, v2);
2087 genRegCopy(cUnit, r0, r12);
2088 } else {
2089 genRegCopy(cUnit, r1, v2);
2090 genRegCopy(cUnit, r0, v1);
2091 }
2092 }
2093 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2094 break;
2095 case kArmThrowDivZero:
2096 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2097 break;
2098 case kArmThrowVerificationError:
2099 loadConstant(cUnit, r0, v1);
2100 loadConstant(cUnit, r1, v2);
2101 funcOffset =
2102 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2103 break;
2104 case kArmThrowNegArraySize:
2105 genRegCopy(cUnit, r0, v1);
2106 funcOffset =
2107 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2108 break;
2109 case kArmThrowInternalError:
2110 genRegCopy(cUnit, r0, v1);
2111 funcOffset =
2112 OFFSETOF_MEMBER(Thread, pThrowInternalErrorFromCode);
2113 break;
2114 case kArmThrowRuntimeException:
2115 genRegCopy(cUnit, r0, v1);
2116 funcOffset =
2117 OFFSETOF_MEMBER(Thread, pThrowRuntimeExceptionFromCode);
2118 break;
2119 case kArmThrowNoSuchMethod:
2120 genRegCopy(cUnit, r0, v1);
2121 funcOffset =
2122 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2123 break;
buzbeeec5adf32011-09-11 15:25:43 -07002124 case kArmThrowStackOverflow:
2125 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002126 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002127 // Restore stack alignment
2128 opRegImm(cUnit, kOpAdd, rSP, cUnit->numSpills * 4);
2129 break;
buzbee5ade1d22011-09-09 14:44:52 -07002130 default:
2131 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2132 }
2133 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002134 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002135 }
2136}
2137
buzbee67bf8852011-08-17 17:51:35 -07002138void oatMethodMIR2LIR(CompilationUnit* cUnit)
2139{
2140 /* Used to hold the labels of each block */
2141 cUnit->blockLabelList =
2142 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2143
2144 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2145 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002146 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002147
2148 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002149
2150 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002151}
2152
2153/* Common initialization routine for an architecture family */
2154bool oatArchInit()
2155{
2156 int i;
2157
2158 for (i = 0; i < kArmLast; i++) {
2159 if (EncodingMap[i].opcode != i) {
2160 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2161 " is wrong: expecting " << i << ", seeing " <<
2162 (int)EncodingMap[i].opcode;
2163 }
2164 }
2165
2166 return oatArchVariantInit();
2167}
2168
2169/* Needed by the Assembler */
2170void oatSetupResourceMasks(ArmLIR* lir)
2171{
2172 setupResourceMasks(lir);
2173}
2174
2175/* Needed by the ld/st optmizatons */
2176ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2177{
2178 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2179}
2180
2181/* Needed by the register allocator */
2182ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2183{
2184 return genRegCopy(cUnit, rDest, rSrc);
2185}
2186
2187/* Needed by the register allocator */
2188void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2189 int srcLo, int srcHi)
2190{
2191 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2192}
2193
2194void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2195 int displacement, int rSrc, OpSize size)
2196{
2197 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2198}
2199
2200void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2201 int displacement, int rSrcLo, int rSrcHi)
2202{
2203 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2204}