blob: a4e211b711cc6c6d67a271f90d0b884bffe0c961 [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
Elliott Hughes81bc5092011-09-30 17:25:59 -0700190 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700191 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
192 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700193 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
194 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
195 loadCurrMethodDirect(cUnit, r1);
196 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700197 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700198 } else {
buzbee1da522d2011-09-04 11:22:20 -0700199 // fast path
200 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700201 // Using fixed register to sync with slow path
202 int rMethod = r1;
203 oatLockTemp(cUnit, rMethod);
204 loadCurrMethodDirect(cUnit, rMethod);
205 int rBase = r0;
206 oatLockTemp(cUnit, rBase);
207 loadWordDisp(cUnit, rMethod,
208 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
209 rBase);
210 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
211 sizeof(int32_t*)* typeIdx, rBase);
212 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700213 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700214 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
215 loadWordDisp(cUnit, rSELF,
216 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
217 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700218 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700219 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
220 skipTarget->defMask = ENCODE_ALL;
221 branchOver->generic.target = (LIR*)skipTarget;
222 rlSrc = oatGetSrc(cUnit, mir, 0);
223 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700224#if ANDROID_SMP != 0
225 if (field->IsVolatile()) {
226 oatGenMemBarrier(cUnit, kST);
227 }
228#endif
buzbee1da522d2011-09-04 11:22:20 -0700229 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700230#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700231 if (field->IsVolatile()) {
232 oatGenMemBarrier(cUnit, kSY);
233 }
buzbee67bf8852011-08-17 17:51:35 -0700234#endif
buzbee1da522d2011-09-04 11:22:20 -0700235 if (isObject) {
236 markGCCard(cUnit, rlSrc.lowReg, rBase);
237 }
238 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700239 }
buzbee67bf8852011-08-17 17:51:35 -0700240}
241
buzbeeed3e9302011-09-23 17:34:19 -0700242STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700243{
buzbee1da522d2011-09-04 11:22:20 -0700244 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700245 uint32_t typeIdx;
246 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700247 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700248#if ANDROID_SMP != 0
249 bool isVolatile = (field == NULL) || field->IsVolatile();
250#else
251 bool isVolatile = false;
252#endif
253 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700254 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700255 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700256 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
257 loadCurrMethodDirect(cUnit, r1);
258 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700259 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700260 } else {
buzbee1da522d2011-09-04 11:22:20 -0700261 // fast path
262 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700263 // Using fixed register to sync with slow path
264 int rMethod = r1;
265 oatLockTemp(cUnit, rMethod);
266 loadCurrMethodDirect(cUnit, r1);
267 int rBase = r0;
268 oatLockTemp(cUnit, rBase);
269 loadWordDisp(cUnit, rMethod,
270 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
271 rBase);
272 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
273 sizeof(int32_t*)* typeIdx, rBase);
274 // TUNING: fast path should fall through
275 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
276 loadWordDisp(cUnit, rSELF,
277 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
278 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700279 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700280 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
281 skipTarget->defMask = ENCODE_ALL;
282 branchOver->generic.target = (LIR*)skipTarget;
283 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
284 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
285 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
286 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700287 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700288 }
buzbee67bf8852011-08-17 17:51:35 -0700289}
290
291
buzbeeed3e9302011-09-23 17:34:19 -0700292STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700293 RegLocation rlResult, RegLocation rlDest)
294{
buzbee1da522d2011-09-04 11:22:20 -0700295 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700296 uint32_t typeIdx;
297 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700298#if ANDROID_SMP != 0
299 bool isVolatile = (field == NULL) || field->IsVolatile();
300#else
301 bool isVolatile = false;
302#endif
buzbee6181f792011-09-29 11:14:04 -0700303 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700304 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700305 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700306 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700307 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
308 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700309 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700310 RegLocation rlResult = oatGetReturnWide(cUnit);
311 storeValueWide(cUnit, rlDest, rlResult);
312 } else {
buzbee1da522d2011-09-04 11:22:20 -0700313 // Fast path
314 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700315 // Using fixed register to sync with slow path
316 int rMethod = r1;
317 oatLockTemp(cUnit, rMethod);
318 loadCurrMethodDirect(cUnit, rMethod);
319 int rBase = r0;
320 oatLockTemp(cUnit, rBase);
321 loadWordDisp(cUnit, rMethod,
322 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
323 rBase);
324 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
325 sizeof(int32_t*)* typeIdx, rBase);
326 // TUNING: fast path should fall through
327 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
328 loadWordDisp(cUnit, rSELF,
329 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
330 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700331 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700332 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
333 skipTarget->defMask = ENCODE_ALL;
334 branchOver->generic.target = (LIR*)skipTarget;
335 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
336 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700337 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
338 rlResult.highReg, INVALID_SREG);
339 oatFreeTemp(cUnit, rBase);
340 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700341 }
buzbee67bf8852011-08-17 17:51:35 -0700342}
343
buzbeeed3e9302011-09-23 17:34:19 -0700344STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700345 RegLocation rlResult, RegLocation rlDest)
346{
buzbee1da522d2011-09-04 11:22:20 -0700347 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700348 uint32_t typeIdx;
349 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700350 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
351 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700352 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700353 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700354 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700355 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700356 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
357 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700358 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
359 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
360 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700361 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700362 RegLocation rlResult = oatGetReturn(cUnit);
363 storeValue(cUnit, rlDest, rlResult);
364 } else {
buzbee1da522d2011-09-04 11:22:20 -0700365 // Fast path
366 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700367 // Using fixed register to sync with slow path
368 int rMethod = r1;
369 oatLockTemp(cUnit, rMethod);
370 loadCurrMethodDirect(cUnit, rMethod);
371 int rBase = r0;
372 oatLockTemp(cUnit, rBase);
373 loadWordDisp(cUnit, rMethod,
374 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
375 rBase);
376 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
377 sizeof(int32_t*)* typeIdx, rBase);
378 // TUNING: fast path should fall through
379 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
380 loadWordDisp(cUnit, rSELF,
381 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
382 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700383 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700384 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
385 skipTarget->defMask = ENCODE_ALL;
386 branchOver->generic.target = (LIR*)skipTarget;
387 rlDest = oatGetDest(cUnit, mir, 0);
388 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700389#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700390 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700391 oatGenMemBarrier(cUnit, kSY);
392 }
buzbee67bf8852011-08-17 17:51:35 -0700393#endif
buzbee1da522d2011-09-04 11:22:20 -0700394 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
395 oatFreeTemp(cUnit, rBase);
396 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700397 }
buzbee67bf8852011-08-17 17:51:35 -0700398}
399
buzbee561227c2011-09-02 15:28:19 -0700400typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
401 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700402
403/*
404 * Bit of a hack here - in leiu of a real scheduling pass,
405 * emit the next instruction in static & direct invoke sequences.
406 */
buzbeeed3e9302011-09-23 17:34:19 -0700407STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700408 DecodedInstruction* dInsn, int state,
409 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700410{
buzbee561227c2011-09-02 15:28:19 -0700411 DCHECK(rollback == NULL);
412 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700413 switch(state) {
414 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700415 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700416 break;
buzbee561227c2011-09-02 15:28:19 -0700417 case 1: // Get method->code_and_direct_methods_
418 loadWordDisp(cUnit, r0,
419 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
420 r0);
buzbee67bf8852011-08-17 17:51:35 -0700421 break;
buzbee561227c2011-09-02 15:28:19 -0700422 case 2: // Grab target method* and target code_
423 loadWordDisp(cUnit, r0,
424 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
425 loadWordDisp(cUnit, r0,
426 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700427 break;
428 default:
429 return -1;
430 }
431 return state + 1;
432}
433
buzbee67bf8852011-08-17 17:51:35 -0700434/*
435 * Bit of a hack here - in leiu of a real scheduling pass,
436 * emit the next instruction in a virtual invoke sequence.
437 * We can use rLR as a temp prior to target address loading
438 * Note also that we'll load the first argument ("this") into
439 * r1 here rather than the standard loadArgRegs.
440 */
buzbeeed3e9302011-09-23 17:34:19 -0700441STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700442 DecodedInstruction* dInsn, int state,
443 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700444{
buzbee561227c2011-09-02 15:28:19 -0700445 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700446 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700447 /*
448 * This is the fast path in which the target virtual method is
449 * fully resolved at compile time.
450 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700451 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
452 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -0700453 CHECK(baseMethod != NULL);
454 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700455 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700456 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700457 rlArg = oatGetSrc(cUnit, mir, 0);
458 loadValueDirectFixed(cUnit, rlArg, r1);
459 break;
buzbee561227c2011-09-02 15:28:19 -0700460 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700461 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700462 // get this->klass_ [use r1, set rLR]
463 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700464 break;
buzbee561227c2011-09-02 15:28:19 -0700465 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
466 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700467 break;
buzbee561227c2011-09-02 15:28:19 -0700468 case 3: // Get target method [use rLR, set r0]
469 loadWordDisp(cUnit, rLR, (target_idx * 4) +
470 art::Array::DataOffset().Int32Value(), r0);
471 break;
472 case 4: // Get the target compiled code address [uses r0, sets rLR]
473 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700474 break;
475 default:
476 return -1;
477 }
478 return state + 1;
479}
480
buzbeeed3e9302011-09-23 17:34:19 -0700481STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700482 DecodedInstruction* dInsn, int state,
483 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700484{
buzbeeed3e9302011-09-23 17:34:19 -0700485 DCHECK(rollback == NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700486 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700487 ArmLIR* skipBranch;
488 ArmLIR* skipTarget;
489 /*
490 * This handles the case in which the base method is not fully
491 * resolved at compile time. We must generate code to test
492 * for resolution a run time, bail to the slow path if not to
493 * fill in all the tables. In the latter case, we'll restart at
494 * at the beginning of the sequence.
495 */
buzbee7b1b86d2011-08-26 18:59:10 -0700496 switch(state) {
497 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700498 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700499 break;
buzbee561227c2011-09-02 15:28:19 -0700500 case 1: // Get method->dex_cache_resolved_methods_
501 loadWordDisp(cUnit, r0,
502 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700503 break;
buzbee561227c2011-09-02 15:28:19 -0700504 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
505 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
506 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700507 break;
buzbee561227c2011-09-02 15:28:19 -0700508 case 3: // Resolved?
509 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
510 // Slowest path, bail to helper, rollback and retry
511 loadWordDisp(cUnit, rSELF,
512 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
513 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700514 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700515 genUnconditionalBranch(cUnit, rollback);
516 // Resume normal slow path
517 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
518 skipTarget->defMask = ENCODE_ALL;
519 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700520 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700521 loadBaseDisp(cUnit, mir, rLR,
522 Method::GetMethodIndexOffset().Int32Value(), r0,
523 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700524 // Load "this" [set r1]
525 rlArg = oatGetSrc(cUnit, mir, 0);
526 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700527 break;
528 case 4:
529 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700530 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700531 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700532 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700533 break;
buzbee561227c2011-09-02 15:28:19 -0700534 case 5:
535 // get this->klass_->vtable_ [usr rLR, set rLR]
536 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700537 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700538 // In load shadow fold vtable_ object header size into method_index_
539 opRegImm(cUnit, kOpAdd, r0,
540 art::Array::DataOffset().Int32Value() / 4);
541 // Get target Method*
542 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
543 break;
544 case 6: // Get the target compiled code address [uses r0, sets rLR]
545 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700546 break;
547 default:
548 return -1;
549 }
550 return state + 1;
551}
552
buzbeeed3e9302011-09-23 17:34:19 -0700553STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700554 DecodedInstruction* dInsn, int callState,
555 NextCallInsn nextCallInsn, ArmLIR* rollback,
556 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700557{
buzbeec0ecd652011-09-25 18:11:54 -0700558 int nextReg = r1;
559 int nextArg = 0;
560 if (skipThis) {
561 nextReg++;
562 nextArg++;
563 }
564 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
565 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
566 rlArg = oatUpdateRawLoc(cUnit, rlArg);
567 if (rlArg.wide && (nextReg <= r2)) {
568 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
569 nextReg++;
570 nextArg++;
571 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700572 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700573 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700574 }
buzbeec0ecd652011-09-25 18:11:54 -0700575 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700576 }
577 return callState;
578}
579
buzbee4a3164f2011-09-03 11:25:10 -0700580// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700581STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700582 DecodedInstruction* dInsn, int state,
583 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700584{
buzbee67bf8852011-08-17 17:51:35 -0700585 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700586 case 0: // Load trampoline target
587 loadWordDisp(cUnit, rSELF,
588 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
589 rLR);
590 // Load r0 with method index
591 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700592 break;
buzbee67bf8852011-08-17 17:51:35 -0700593 default:
594 return -1;
595 }
596 return state + 1;
597}
598
buzbee67bf8852011-08-17 17:51:35 -0700599/*
600 * Interleave launch code for INVOKE_SUPER. See comments
601 * for nextVCallIns.
602 */
buzbeeed3e9302011-09-23 17:34:19 -0700603STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700604 DecodedInstruction* dInsn, int state,
605 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700606{
buzbee4a3164f2011-09-03 11:25:10 -0700607 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700608 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700609 /*
610 * This is the fast path in which the target virtual method is
611 * fully resolved at compile time. Note also that this path assumes
612 * that the check to verify that the target method index falls
613 * within the size of the super's vtable has been done at compile-time.
614 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700615 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
616 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700617 CHECK(baseMethod != NULL);
618 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
619 CHECK(superClass != NULL);
620 int32_t target_idx = baseMethod->GetMethodIndex();
621 CHECK(superClass->GetVTable()->GetLength() > target_idx);
622 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
623 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700624 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700625 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700626 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700627 // Load "this" [set r1]
628 rlArg = oatGetSrc(cUnit, mir, 0);
629 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700630 // Get method->declaring_class_ [use r0, set rLR]
631 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
632 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700633 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700634 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700635 break;
636 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
637 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
638 rLR);
639 break;
640 case 2: // Get ...->super_class_->vtable [u/s rLR]
641 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
642 break;
643 case 3: // Get target method [use rLR, set r0]
644 loadWordDisp(cUnit, rLR, (target_idx * 4) +
645 art::Array::DataOffset().Int32Value(), r0);
646 break;
647 case 4: // Get the target compiled code address [uses r0, sets rLR]
648 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
649 break;
buzbee67bf8852011-08-17 17:51:35 -0700650 default:
651 return -1;
652 }
buzbee4a3164f2011-09-03 11:25:10 -0700653 return state + 1;
654}
655
656/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700657STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700658 DecodedInstruction* dInsn, int state,
659 ArmLIR* rollback)
660{
buzbeeed3e9302011-09-23 17:34:19 -0700661 DCHECK(rollback == NULL);
buzbee4a3164f2011-09-03 11:25:10 -0700662 RegLocation rlArg;
663 ArmLIR* skipBranch;
664 ArmLIR* skipTarget;
665 int tReg;
666 /*
667 * This handles the case in which the base method is not fully
668 * resolved at compile time. We must generate code to test
669 * for resolution a run time, bail to the slow path if not to
670 * fill in all the tables. In the latter case, we'll restart at
671 * at the beginning of the sequence.
672 */
673 switch(state) {
674 case 0: // Get the current Method* [sets r0]
675 loadCurrMethodDirect(cUnit, r0);
676 break;
677 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
678 loadWordDisp(cUnit, r0,
679 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
680 break;
681 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
682 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
683 art::Array::DataOffset().Int32Value(), rLR);
684 break;
685 case 3: // Resolved?
686 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
687 // Slowest path, bail to helper, rollback and retry
688 loadWordDisp(cUnit, rSELF,
689 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
690 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700691 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700692 genUnconditionalBranch(cUnit, rollback);
693 // Resume normal slow path
694 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
695 skipTarget->defMask = ENCODE_ALL;
696 skipBranch->generic.target = (LIR*)skipTarget;
697 // Get base_method->method_index [usr rLR, set rLR]
698 loadBaseDisp(cUnit, mir, rLR,
699 Method::GetMethodIndexOffset().Int32Value(), rLR,
700 kUnsignedHalf, INVALID_SREG);
701 // Load "this" [set r1]
702 rlArg = oatGetSrc(cUnit, mir, 0);
703 loadValueDirectFixed(cUnit, rlArg, r1);
704 // Load curMethod->declaring_class_ [uses r0, sets r0]
705 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
706 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700707 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700708 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700709 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700710 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
711 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700712 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700713 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700714 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700715 // Range check, throw NSM on failure
716 tReg = oatAllocTemp(cUnit);
717 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
718 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700719 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
720 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700721 oatFreeTemp(cUnit, tReg);
722 }
buzbee6a0f7f52011-09-05 16:14:20 -0700723 // Adjust vtable_ base past object header
724 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700725 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700726 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700727 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700728 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700729 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
730 break;
731 default:
732 return -1;
733 }
buzbee67bf8852011-08-17 17:51:35 -0700734 return state + 1;
735}
736
737/*
738 * Load up to 5 arguments, the first three of which will be in
739 * r1 .. r3. On entry r0 contains the current method pointer,
740 * and as part of the load sequence, it must be replaced with
741 * the target method pointer. Note, this may also be called
742 * for "range" variants if the number of arguments is 5 or fewer.
743 */
buzbeeed3e9302011-09-23 17:34:19 -0700744STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700745 DecodedInstruction* dInsn, int callState,
746 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700747 NextCallInsn nextCallInsn, ArmLIR* rollback,
748 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700749{
750 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700751
752 /* If no arguments, just return */
753 if (dInsn->vA == 0)
754 return callState;
755
buzbee561227c2011-09-02 15:28:19 -0700756 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700757
buzbeec0ecd652011-09-25 18:11:54 -0700758 DCHECK_LE(dInsn->vA, 5U);
759 if (dInsn->vA > 3) {
760 uint32_t nextUse = 3;
761 //Detect special case of wide arg spanning arg3/arg4
762 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
763 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
764 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
765 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
766 rlUse2.wide) {
767 int reg;
768 // Wide spans, we need the 2nd half of uses[2].
769 rlArg = oatUpdateLocWide(cUnit, rlUse2);
770 if (rlArg.location == kLocPhysReg) {
771 reg = rlArg.highReg;
772 } else {
773 // r2 & r3 can safely be used here
774 reg = r3;
775 loadWordDisp(cUnit, rSP, rlArg.spOffset + 4, reg);
776 callState = nextCallInsn(cUnit, mir, dInsn, callState,
777 rollback);
778 }
779 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
780 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
781 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
782 nextUse++;
783 }
784 // Loop through the rest
785 while (nextUse < dInsn->vA) {
786 int lowReg;
787 int highReg;
788 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
789 rlArg = oatUpdateRawLoc(cUnit, rlArg);
790 if (rlArg.location == kLocPhysReg) {
791 lowReg = rlArg.lowReg;
792 highReg = rlArg.highReg;
793 } else {
794 lowReg = r2;
795 highReg = r3;
796 if (rlArg.wide) {
797 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
798 } else {
799 loadValueDirectFixed(cUnit, rlArg, lowReg);
800 }
801 callState = nextCallInsn(cUnit, mir, dInsn, callState,
802 rollback);
803 }
804 int outsOffset = (nextUse + 1) * 4;
805 if (rlArg.wide) {
806 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
807 nextUse += 2;
808 } else {
809 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
810 nextUse++;
811 }
buzbee561227c2011-09-02 15:28:19 -0700812 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700813 }
buzbee67bf8852011-08-17 17:51:35 -0700814 }
815
buzbeec0ecd652011-09-25 18:11:54 -0700816 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
817 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700818
buzbee6a0f7f52011-09-05 16:14:20 -0700819 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700820 // Load direct & need a "this" null check?
821 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700822 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700823 }
824 return callState;
825}
826
827/*
828 * May have 0+ arguments (also used for jumbo). Note that
829 * source virtual registers may be in physical registers, so may
830 * need to be flushed to home location before copying. This
831 * applies to arg3 and above (see below).
832 *
833 * Two general strategies:
834 * If < 20 arguments
835 * Pass args 3-18 using vldm/vstm block copy
836 * Pass arg0, arg1 & arg2 in r1-r3
837 * If 20+ arguments
838 * Pass args arg19+ using memcpy block copy
839 * Pass arg0, arg1 & arg2 in r1-r3
840 *
841 */
buzbeeed3e9302011-09-23 17:34:19 -0700842STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700843 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700844 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700845 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700846{
847 int firstArg = dInsn->vC;
848 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700849
buzbee67bf8852011-08-17 17:51:35 -0700850 // If we can treat it as non-range (Jumbo ops will use range form)
851 if (numArgs <= 5)
852 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700853 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700854 /*
855 * Make sure range list doesn't span the break between in normal
856 * Dalvik vRegs and the ins.
857 */
buzbee1b4c8592011-08-31 10:43:51 -0700858 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700859 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700860 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
861 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700862 }
863
864 /*
865 * First load the non-register arguments. Both forms expect all
866 * of the source arguments to be in their home frame location, so
867 * scan the sReg names and flush any that have been promoted to
868 * frame backing storage.
869 */
870 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700871 for (int nextArg = 0; nextArg < numArgs;) {
872 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700873 if (loc.wide) {
874 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700875 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee1b4c8592011-08-31 10:43:51 -0700876 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
877 loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700878 }
buzbeec0ecd652011-09-25 18:11:54 -0700879 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700880 } else {
881 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700882 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee1b4c8592011-08-31 10:43:51 -0700883 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700884 }
buzbeec0ecd652011-09-25 18:11:54 -0700885 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700886 }
887 }
888
889 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
890 int outsOffset = 4 /* Method* */ + (3 * 4);
891 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700892 // Generate memcpy
893 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
894 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700895 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
896 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700897 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700898 // Restore Method*
899 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700900 } else {
901 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700902 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700903 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700904 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700905 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
906 //TUNING: loosen barrier
907 ld->defMask = ENCODE_ALL;
908 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700909 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700910 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700911 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700912 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
913 setMemRefType(st, false /* isLoad */, kDalvikReg);
914 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700915 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700916 }
917
buzbeec0ecd652011-09-25 18:11:54 -0700918 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
919 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700920
buzbee561227c2011-09-02 15:28:19 -0700921 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700922 return callState;
923}
924
buzbee2a475e72011-09-07 17:19:17 -0700925#ifdef DISPLAY_MISSING_TARGETS
926// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700927STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700928{
929 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
930 loadWordDisp(cUnit, rSELF,
931 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
932 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
933 target->defMask = -1;
934 branchOver->generic.target = (LIR*)target;
935}
936#endif
937
buzbeeed3e9302011-09-23 17:34:19 -0700938STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700939 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700940{
941 DecodedInstruction* dInsn = &mir->dalvikInsn;
942 int callState = 0;
943 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700944 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700945 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700946 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700947
buzbee109bd6a2011-09-06 13:58:41 -0700948 // Explicit register usage
949 oatLockCallTemps(cUnit);
950
buzbee561227c2011-09-02 15:28:19 -0700951 if (range) {
952 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700953 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700954 } else {
955 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700956 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700957 }
buzbee67bf8852011-08-17 17:51:35 -0700958 // Finish up any of the call sequence not interleaved in arg loading
959 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700960 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700961 }
buzbee2a475e72011-09-07 17:19:17 -0700962#ifdef DISPLAY_MISSING_TARGETS
963 genShowTarget(cUnit);
964#endif
buzbeeec5adf32011-09-11 15:25:43 -0700965 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700966 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700967}
968
buzbee4a3164f2011-09-03 11:25:10 -0700969/*
970 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
971 * which will locate the target and continue on via a tail call.
972 */
buzbeeed3e9302011-09-23 17:34:19 -0700973STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -0700974{
975 DecodedInstruction* dInsn = &mir->dalvikInsn;
976 int callState = 0;
977 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -0700978 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -0700979
980 // Explicit register usage
981 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700982 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700983 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700984 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
985 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700986 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -0700987 false);
buzbee67bf8852011-08-17 17:51:35 -0700988 else
989 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -0700990 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -0700991 // Finish up any of the call sequence not interleaved in arg loading
992 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700993 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700994 }
buzbee2a475e72011-09-07 17:19:17 -0700995#ifdef DISPLAY_MISSING_TARGETS
996 genShowTarget(cUnit);
997#endif
buzbeeec5adf32011-09-11 15:25:43 -0700998 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700999 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001000}
1001
buzbeeed3e9302011-09-23 17:34:19 -07001002STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001003{
1004 DecodedInstruction* dInsn = &mir->dalvikInsn;
1005 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001006 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001007 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1008 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -07001009 NextCallInsn nextCallInsn;
1010 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001011 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001012
1013 // Explicit register usage
1014 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001015 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -07001016 fastPath = false;
1017 } else {
1018 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
1019 if (superClass == NULL) {
1020 fastPath = false;
1021 } else {
1022 int32_t target_idx = baseMethod->GetMethodIndex();
1023 if (superClass->GetVTable()->GetLength() <= target_idx) {
1024 fastPath = false;
1025 } else {
1026 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1027 }
1028 }
1029 }
1030 if (fastPath) {
1031 nextCallInsn = nextSuperCallInsn;
1032 rollback = NULL;
1033 } else {
1034 nextCallInsn = nextSuperCallInsnSP;
1035 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1036 rollback->defMask = -1;
1037 }
buzbee67bf8852011-08-17 17:51:35 -07001038 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001039 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001040 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001041 else
buzbeec0ecd652011-09-25 18:11:54 -07001042 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001043 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001044 // Finish up any of the call sequence not interleaved in arg loading
1045 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001046 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001047 }
buzbee2a475e72011-09-07 17:19:17 -07001048#ifdef DISPLAY_MISSING_TARGETS
1049 genShowTarget(cUnit);
1050#endif
buzbeeec5adf32011-09-11 15:25:43 -07001051 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001052 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001053}
1054
buzbeeed3e9302011-09-23 17:34:19 -07001055STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001056{
1057 DecodedInstruction* dInsn = &mir->dalvikInsn;
1058 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001059 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001060 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1061 Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -07001062 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001063 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee7b1b86d2011-08-26 18:59:10 -07001064
buzbee109bd6a2011-09-06 13:58:41 -07001065 // Explicit register usage
1066 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001067 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001068 // Slow path
1069 nextCallInsn = nextVCallInsnSP;
1070 // If we need a slow-path callout, we'll restart here
1071 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1072 rollback->defMask = -1;
1073 } else {
1074 // Fast path
1075 nextCallInsn = nextVCallInsn;
1076 rollback = NULL;
1077 }
buzbee67bf8852011-08-17 17:51:35 -07001078 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001079 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001080 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001081 else
buzbeec0ecd652011-09-25 18:11:54 -07001082 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001083 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001084 // Finish up any of the call sequence not interleaved in arg loading
1085 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001086 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001087 }
buzbee2a475e72011-09-07 17:19:17 -07001088#ifdef DISPLAY_MISSING_TARGETS
1089 genShowTarget(cUnit);
1090#endif
buzbeeec5adf32011-09-11 15:25:43 -07001091 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001092 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001093}
1094
buzbeeed3e9302011-09-23 17:34:19 -07001095STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001096 BasicBlock* bb, ArmLIR* labelList)
1097{
1098 bool res = false; // Assume success
1099 RegLocation rlSrc[3];
1100 RegLocation rlDest = badLoc;
1101 RegLocation rlResult = badLoc;
1102 Opcode opcode = mir->dalvikInsn.opcode;
1103
1104 /* Prep Src and Dest locations */
1105 int nextSreg = 0;
1106 int nextLoc = 0;
1107 int attrs = oatDataFlowAttributes[opcode];
1108 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1109 if (attrs & DF_UA) {
1110 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1111 nextSreg++;
1112 } else if (attrs & DF_UA_WIDE) {
1113 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1114 nextSreg + 1);
1115 nextSreg+= 2;
1116 }
1117 if (attrs & DF_UB) {
1118 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1119 nextSreg++;
1120 } else if (attrs & DF_UB_WIDE) {
1121 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1122 nextSreg + 1);
1123 nextSreg+= 2;
1124 }
1125 if (attrs & DF_UC) {
1126 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1127 } else if (attrs & DF_UC_WIDE) {
1128 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1129 nextSreg + 1);
1130 }
1131 if (attrs & DF_DA) {
1132 rlDest = oatGetDest(cUnit, mir, 0);
1133 } else if (attrs & DF_DA_WIDE) {
1134 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1135 }
1136
1137 switch(opcode) {
1138 case OP_NOP:
1139 break;
1140
1141 case OP_MOVE_EXCEPTION:
1142 int exOffset;
1143 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001144 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001145 resetReg = oatAllocTemp(cUnit);
1146 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1147 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1148 loadConstant(cUnit, resetReg, 0);
1149 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1150 storeValue(cUnit, rlDest, rlResult);
1151 break;
1152
1153 case OP_RETURN_VOID:
buzbeec0ecd652011-09-25 18:11:54 -07001154 genSuspendPoll(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001155 break;
1156
1157 case OP_RETURN:
1158 case OP_RETURN_OBJECT:
buzbeec1f45042011-09-21 16:03:19 -07001159 genSuspendPoll(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001160 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001161 break;
1162
1163 case OP_RETURN_WIDE:
buzbeec1f45042011-09-21 16:03:19 -07001164 genSuspendPoll(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001165 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001166 break;
1167
1168 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001169 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001170 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001171 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001172 break;
1173
1174 case OP_MOVE_RESULT:
1175 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001176 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001177 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001178 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001179 break;
1180
1181 case OP_MOVE:
1182 case OP_MOVE_OBJECT:
1183 case OP_MOVE_16:
1184 case OP_MOVE_OBJECT_16:
1185 case OP_MOVE_FROM16:
1186 case OP_MOVE_OBJECT_FROM16:
1187 storeValue(cUnit, rlDest, rlSrc[0]);
1188 break;
1189
1190 case OP_MOVE_WIDE:
1191 case OP_MOVE_WIDE_16:
1192 case OP_MOVE_WIDE_FROM16:
1193 storeValueWide(cUnit, rlDest, rlSrc[0]);
1194 break;
1195
1196 case OP_CONST:
1197 case OP_CONST_4:
1198 case OP_CONST_16:
1199 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1200 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1201 storeValue(cUnit, rlDest, rlResult);
1202 break;
1203
1204 case OP_CONST_HIGH16:
1205 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1206 loadConstantNoClobber(cUnit, rlResult.lowReg,
1207 mir->dalvikInsn.vB << 16);
1208 storeValue(cUnit, rlDest, rlResult);
1209 break;
1210
1211 case OP_CONST_WIDE_16:
1212 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001213 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1214 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1215 mir->dalvikInsn.vB,
1216 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001217 storeValueWide(cUnit, rlDest, rlResult);
1218 break;
1219
1220 case OP_CONST_WIDE:
1221 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1222 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001223 mir->dalvikInsn.vB_wide & 0xffffffff,
1224 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001225 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001226 break;
1227
1228 case OP_CONST_WIDE_HIGH16:
1229 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1230 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1231 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001232 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001233 break;
1234
1235 case OP_MONITOR_ENTER:
1236 genMonitorEnter(cUnit, mir, rlSrc[0]);
1237 break;
1238
1239 case OP_MONITOR_EXIT:
1240 genMonitorExit(cUnit, mir, rlSrc[0]);
1241 break;
1242
1243 case OP_CHECK_CAST:
1244 genCheckCast(cUnit, mir, rlSrc[0]);
1245 break;
1246
1247 case OP_INSTANCE_OF:
1248 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1249 break;
1250
1251 case OP_NEW_INSTANCE:
1252 genNewInstance(cUnit, mir, rlDest);
1253 break;
1254
1255 case OP_THROW:
1256 genThrow(cUnit, mir, rlSrc[0]);
1257 break;
1258
buzbee5ade1d22011-09-09 14:44:52 -07001259 case OP_THROW_VERIFICATION_ERROR:
1260 loadWordDisp(cUnit, rSELF,
1261 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1262 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1263 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001264 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001265 break;
1266
buzbee67bf8852011-08-17 17:51:35 -07001267 case OP_ARRAY_LENGTH:
1268 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001269 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001270 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001271 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001272 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1273 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1274 rlResult.lowReg);
1275 storeValue(cUnit, rlDest, rlResult);
1276 break;
1277
1278 case OP_CONST_STRING:
1279 case OP_CONST_STRING_JUMBO:
1280 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1281 break;
1282
1283 case OP_CONST_CLASS:
1284 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1285 break;
1286
1287 case OP_FILL_ARRAY_DATA:
1288 genFillArrayData(cUnit, mir, rlSrc[0]);
1289 break;
1290
1291 case OP_FILLED_NEW_ARRAY:
1292 genFilledNewArray(cUnit, mir, false /* not range */);
1293 break;
1294
1295 case OP_FILLED_NEW_ARRAY_RANGE:
1296 genFilledNewArray(cUnit, mir, true /* range */);
1297 break;
1298
1299 case OP_NEW_ARRAY:
1300 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1301 break;
1302
1303 case OP_GOTO:
1304 case OP_GOTO_16:
1305 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001306 if (bb->taken->startOffset <= mir->offset) {
1307 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001308 }
1309 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1310 break;
1311
1312 case OP_PACKED_SWITCH:
1313 genPackedSwitch(cUnit, mir, rlSrc[0]);
1314 break;
1315
1316 case OP_SPARSE_SWITCH:
1317 genSparseSwitch(cUnit, mir, rlSrc[0]);
1318 break;
1319
1320 case OP_CMPL_FLOAT:
1321 case OP_CMPG_FLOAT:
1322 case OP_CMPL_DOUBLE:
1323 case OP_CMPG_DOUBLE:
1324 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1325 break;
1326
1327 case OP_CMP_LONG:
1328 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1329 break;
1330
1331 case OP_IF_EQ:
1332 case OP_IF_NE:
1333 case OP_IF_LT:
1334 case OP_IF_GE:
1335 case OP_IF_GT:
1336 case OP_IF_LE: {
1337 bool backwardBranch;
1338 ArmConditionCode cond;
1339 backwardBranch = (bb->taken->startOffset <= mir->offset);
1340 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001341 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001342 }
1343 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1344 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1345 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1346 switch(opcode) {
1347 case OP_IF_EQ:
1348 cond = kArmCondEq;
1349 break;
1350 case OP_IF_NE:
1351 cond = kArmCondNe;
1352 break;
1353 case OP_IF_LT:
1354 cond = kArmCondLt;
1355 break;
1356 case OP_IF_GE:
1357 cond = kArmCondGe;
1358 break;
1359 case OP_IF_GT:
1360 cond = kArmCondGt;
1361 break;
1362 case OP_IF_LE:
1363 cond = kArmCondLe;
1364 break;
1365 default:
1366 cond = (ArmConditionCode)0;
1367 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1368 }
1369 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1370 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1371 break;
1372 }
1373
1374 case OP_IF_EQZ:
1375 case OP_IF_NEZ:
1376 case OP_IF_LTZ:
1377 case OP_IF_GEZ:
1378 case OP_IF_GTZ:
1379 case OP_IF_LEZ: {
1380 bool backwardBranch;
1381 ArmConditionCode cond;
1382 backwardBranch = (bb->taken->startOffset <= mir->offset);
1383 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001384 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001385 }
1386 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1387 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1388 switch(opcode) {
1389 case OP_IF_EQZ:
1390 cond = kArmCondEq;
1391 break;
1392 case OP_IF_NEZ:
1393 cond = kArmCondNe;
1394 break;
1395 case OP_IF_LTZ:
1396 cond = kArmCondLt;
1397 break;
1398 case OP_IF_GEZ:
1399 cond = kArmCondGe;
1400 break;
1401 case OP_IF_GTZ:
1402 cond = kArmCondGt;
1403 break;
1404 case OP_IF_LEZ:
1405 cond = kArmCondLe;
1406 break;
1407 default:
1408 cond = (ArmConditionCode)0;
1409 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1410 }
1411 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1412 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1413 break;
1414 }
1415
1416 case OP_AGET_WIDE:
1417 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1418 break;
1419 case OP_AGET:
1420 case OP_AGET_OBJECT:
1421 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1422 break;
1423 case OP_AGET_BOOLEAN:
1424 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1425 rlDest, 0);
1426 break;
1427 case OP_AGET_BYTE:
1428 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1429 break;
1430 case OP_AGET_CHAR:
1431 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1432 rlDest, 1);
1433 break;
1434 case OP_AGET_SHORT:
1435 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1436 break;
1437 case OP_APUT_WIDE:
1438 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1439 break;
1440 case OP_APUT:
1441 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1442 break;
1443 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001444 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001445 break;
1446 case OP_APUT_SHORT:
1447 case OP_APUT_CHAR:
1448 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1449 rlSrc[0], 1);
1450 break;
1451 case OP_APUT_BYTE:
1452 case OP_APUT_BOOLEAN:
1453 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1454 rlSrc[0], 0);
1455 break;
1456
1457 case OP_IGET_WIDE:
1458 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001459 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001460 break;
1461
1462 case OP_IGET:
1463 case OP_IGET_VOLATILE:
1464 case OP_IGET_OBJECT:
1465 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001466 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001467 break;
1468
1469 case OP_IGET_BOOLEAN:
1470 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001471 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001472 break;
1473
1474 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001475 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001476 break;
1477
1478 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001479 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001480 break;
1481
1482 case OP_IPUT_WIDE:
1483 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001484 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001485 break;
1486
1487 case OP_IPUT_OBJECT:
1488 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001489 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001490 break;
1491
1492 case OP_IPUT:
1493 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001494 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001495 break;
1496
1497 case OP_IPUT_BOOLEAN:
1498 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001499 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001500 break;
1501
1502 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001503 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001504 break;
1505
1506 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001507 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001508 break;
1509
1510 case OP_SGET:
1511 case OP_SGET_OBJECT:
1512 case OP_SGET_BOOLEAN:
1513 case OP_SGET_BYTE:
1514 case OP_SGET_CHAR:
1515 case OP_SGET_SHORT:
1516 genSget(cUnit, mir, rlResult, rlDest);
1517 break;
1518
1519 case OP_SGET_WIDE:
1520 genSgetWide(cUnit, mir, rlResult, rlDest);
1521 break;
1522
1523 case OP_SPUT:
1524 case OP_SPUT_OBJECT:
1525 case OP_SPUT_BOOLEAN:
1526 case OP_SPUT_BYTE:
1527 case OP_SPUT_CHAR:
1528 case OP_SPUT_SHORT:
1529 genSput(cUnit, mir, rlSrc[0]);
1530 break;
1531
1532 case OP_SPUT_WIDE:
1533 genSputWide(cUnit, mir, rlSrc[0]);
1534 break;
1535
1536 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001537 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1538 true /*range*/);
1539 break;
buzbee67bf8852011-08-17 17:51:35 -07001540 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001541 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1542 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001543 break;
1544
1545 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001546 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1547 false /*range*/);
1548 break;
buzbee67bf8852011-08-17 17:51:35 -07001549 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001550 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1551 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001552 break;
1553
1554 case OP_INVOKE_VIRTUAL:
1555 case OP_INVOKE_VIRTUAL_RANGE:
1556 genInvokeVirtual(cUnit, mir);
1557 break;
1558
1559 case OP_INVOKE_SUPER:
1560 case OP_INVOKE_SUPER_RANGE:
1561 genInvokeSuper(cUnit, mir);
1562 break;
1563
1564 case OP_INVOKE_INTERFACE:
1565 case OP_INVOKE_INTERFACE_RANGE:
1566 genInvokeInterface(cUnit, mir);
1567 break;
1568
1569 case OP_NEG_INT:
1570 case OP_NOT_INT:
1571 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1572 break;
1573
1574 case OP_NEG_LONG:
1575 case OP_NOT_LONG:
1576 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1577 break;
1578
1579 case OP_NEG_FLOAT:
1580 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1581 break;
1582
1583 case OP_NEG_DOUBLE:
1584 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1585 break;
1586
1587 case OP_INT_TO_LONG:
1588 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1589 if (rlSrc[0].location == kLocPhysReg) {
1590 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1591 } else {
1592 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1593 }
1594 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1595 rlResult.lowReg, 31);
1596 storeValueWide(cUnit, rlDest, rlResult);
1597 break;
1598
1599 case OP_LONG_TO_INT:
1600 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1601 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1602 storeValue(cUnit, rlDest, rlSrc[0]);
1603 break;
1604
1605 case OP_INT_TO_BYTE:
1606 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1607 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1608 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1609 storeValue(cUnit, rlDest, rlResult);
1610 break;
1611
1612 case OP_INT_TO_SHORT:
1613 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1614 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1615 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1616 storeValue(cUnit, rlDest, rlResult);
1617 break;
1618
1619 case OP_INT_TO_CHAR:
1620 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1621 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1622 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1623 storeValue(cUnit, rlDest, rlResult);
1624 break;
1625
1626 case OP_INT_TO_FLOAT:
1627 case OP_INT_TO_DOUBLE:
1628 case OP_LONG_TO_FLOAT:
1629 case OP_LONG_TO_DOUBLE:
1630 case OP_FLOAT_TO_INT:
1631 case OP_FLOAT_TO_LONG:
1632 case OP_FLOAT_TO_DOUBLE:
1633 case OP_DOUBLE_TO_INT:
1634 case OP_DOUBLE_TO_LONG:
1635 case OP_DOUBLE_TO_FLOAT:
1636 genConversion(cUnit, mir);
1637 break;
1638
1639 case OP_ADD_INT:
1640 case OP_SUB_INT:
1641 case OP_MUL_INT:
1642 case OP_DIV_INT:
1643 case OP_REM_INT:
1644 case OP_AND_INT:
1645 case OP_OR_INT:
1646 case OP_XOR_INT:
1647 case OP_SHL_INT:
1648 case OP_SHR_INT:
1649 case OP_USHR_INT:
1650 case OP_ADD_INT_2ADDR:
1651 case OP_SUB_INT_2ADDR:
1652 case OP_MUL_INT_2ADDR:
1653 case OP_DIV_INT_2ADDR:
1654 case OP_REM_INT_2ADDR:
1655 case OP_AND_INT_2ADDR:
1656 case OP_OR_INT_2ADDR:
1657 case OP_XOR_INT_2ADDR:
1658 case OP_SHL_INT_2ADDR:
1659 case OP_SHR_INT_2ADDR:
1660 case OP_USHR_INT_2ADDR:
1661 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1662 break;
1663
1664 case OP_ADD_LONG:
1665 case OP_SUB_LONG:
1666 case OP_MUL_LONG:
1667 case OP_DIV_LONG:
1668 case OP_REM_LONG:
1669 case OP_AND_LONG:
1670 case OP_OR_LONG:
1671 case OP_XOR_LONG:
1672 case OP_ADD_LONG_2ADDR:
1673 case OP_SUB_LONG_2ADDR:
1674 case OP_MUL_LONG_2ADDR:
1675 case OP_DIV_LONG_2ADDR:
1676 case OP_REM_LONG_2ADDR:
1677 case OP_AND_LONG_2ADDR:
1678 case OP_OR_LONG_2ADDR:
1679 case OP_XOR_LONG_2ADDR:
1680 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1681 break;
1682
buzbee67bf8852011-08-17 17:51:35 -07001683 case OP_SHL_LONG:
1684 case OP_SHR_LONG:
1685 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001686 case OP_SHL_LONG_2ADDR:
1687 case OP_SHR_LONG_2ADDR:
1688 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001689 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1690 break;
1691
1692 case OP_ADD_FLOAT:
1693 case OP_SUB_FLOAT:
1694 case OP_MUL_FLOAT:
1695 case OP_DIV_FLOAT:
1696 case OP_REM_FLOAT:
1697 case OP_ADD_FLOAT_2ADDR:
1698 case OP_SUB_FLOAT_2ADDR:
1699 case OP_MUL_FLOAT_2ADDR:
1700 case OP_DIV_FLOAT_2ADDR:
1701 case OP_REM_FLOAT_2ADDR:
1702 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1703 break;
1704
1705 case OP_ADD_DOUBLE:
1706 case OP_SUB_DOUBLE:
1707 case OP_MUL_DOUBLE:
1708 case OP_DIV_DOUBLE:
1709 case OP_REM_DOUBLE:
1710 case OP_ADD_DOUBLE_2ADDR:
1711 case OP_SUB_DOUBLE_2ADDR:
1712 case OP_MUL_DOUBLE_2ADDR:
1713 case OP_DIV_DOUBLE_2ADDR:
1714 case OP_REM_DOUBLE_2ADDR:
1715 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1716 break;
1717
1718 case OP_RSUB_INT:
1719 case OP_ADD_INT_LIT16:
1720 case OP_MUL_INT_LIT16:
1721 case OP_DIV_INT_LIT16:
1722 case OP_REM_INT_LIT16:
1723 case OP_AND_INT_LIT16:
1724 case OP_OR_INT_LIT16:
1725 case OP_XOR_INT_LIT16:
1726 case OP_ADD_INT_LIT8:
1727 case OP_RSUB_INT_LIT8:
1728 case OP_MUL_INT_LIT8:
1729 case OP_DIV_INT_LIT8:
1730 case OP_REM_INT_LIT8:
1731 case OP_AND_INT_LIT8:
1732 case OP_OR_INT_LIT8:
1733 case OP_XOR_INT_LIT8:
1734 case OP_SHL_INT_LIT8:
1735 case OP_SHR_INT_LIT8:
1736 case OP_USHR_INT_LIT8:
1737 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1738 break;
1739
1740 default:
1741 res = true;
1742 }
1743 return res;
1744}
1745
buzbeeed3e9302011-09-23 17:34:19 -07001746STATIC const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001747 "kMirOpPhi",
1748 "kMirOpNullNRangeUpCheck",
1749 "kMirOpNullNRangeDownCheck",
1750 "kMirOpLowerBound",
1751 "kMirOpPunt",
1752 "kMirOpCheckInlinePrediction",
1753};
1754
1755/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001756STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001757{
1758 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1759 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1760 strcpy(msg, extendedMIROpNames[opOffset]);
1761 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1762
1763 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1764 case kMirOpPhi: {
1765 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1766 op->flags.isNop = true;
1767 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1768 break;
1769 }
1770 default:
1771 break;
1772 }
1773}
1774
1775/* If there are any ins passed in registers that have not been promoted
1776 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001777 * Note: at this pointCopy any ins that are passed in register to their
1778 * home location */
buzbeeed3e9302011-09-23 17:34:19 -07001779STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001780{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001781 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001782 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001783 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1784 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001785 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001786 int startLoc = cUnit->method->NumRegisters() -
1787 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001788 for (int i = 0; i < inRegs; i++) {
1789 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001790 //TUNING: be smarter about flushing ins to frame
1791 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001792 if (loc.location == kLocPhysReg) {
1793 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001794 }
1795 }
1796
1797 // Handle special case of wide argument half in regs, half in frame
1798 if (inRegs == 3) {
1799 RegLocation loc = cUnit->regLocation[startLoc + 2];
1800 if (loc.wide && loc.location == kLocPhysReg) {
1801 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001802 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001803 inRegs++;
1804 }
1805 }
1806
1807 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001808 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001809 RegLocation loc = cUnit->regLocation[startLoc + i];
1810 if (loc.fpLocation == kLocPhysReg) {
1811 loc.location = kLocPhysReg;
1812 loc.fp = true;
1813 loc.lowReg = loc.fpLowReg;
1814 loc.highReg = loc.fpHighReg;
1815 }
1816 if (loc.location == kLocPhysReg) {
1817 if (loc.wide) {
buzbeeb29e4d12011-09-26 15:05:48 -07001818 if (loc.fp && (loc.lowReg & 1) != 0) {
1819 // Misaligned - need to load as a pair of singles
1820 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
1821 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
1822 } else {
1823 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1824 loc.lowReg, loc.highReg, INVALID_SREG);
1825 }
buzbee67bf8852011-08-17 17:51:35 -07001826 i++;
1827 } else {
buzbee561227c2011-09-02 15:28:19 -07001828 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001829 }
1830 }
1831 i++;
1832 }
1833}
1834
1835/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001836STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001837{
1838 MIR* mir;
1839 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1840 int blockId = bb->id;
1841
1842 cUnit->curBlock = bb;
1843 labelList[blockId].operands[0] = bb->startOffset;
1844
1845 /* Insert the block label */
1846 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1847 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1848
buzbee6181f792011-09-29 11:14:04 -07001849 /* Reset local optimization data on block boundaries */
1850 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001851 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001852 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001853
1854 ArmLIR* headLIR = NULL;
1855
buzbeebbaf8942011-10-02 13:08:29 -07001856 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001857 if (bb->blockType == kEntryBlock) {
1858 /*
1859 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1860 * mechanism know so it doesn't try to use any of them when
1861 * expanding the frame or flushing. This leaves the utility
1862 * code with a single temp: r12. This should be enough.
1863 */
1864 oatLockTemp(cUnit, r0);
1865 oatLockTemp(cUnit, r1);
1866 oatLockTemp(cUnit, r2);
1867 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001868
1869 /*
1870 * We can safely skip the stack overflow check if we're
1871 * a leaf *and* our frame size < fudge factor.
1872 */
1873 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1874 ((size_t)cUnit->frameSize <
1875 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001876 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001877 if (!skipOverflowCheck) {
1878 /* Load stack limit */
1879 loadWordDisp(cUnit, rSELF,
1880 art::Thread::StackEndOffset().Int32Value(), r12);
1881 }
buzbee67bf8852011-08-17 17:51:35 -07001882 /* Spill core callee saves */
1883 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1884 /* Need to spill any FP regs? */
1885 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001886 /*
1887 * NOTE: fp spills are a little different from core spills in that
1888 * they are pushed as a contiguous block. When promoting from
1889 * the fp set, we must allocate all singles from s16..highest-promoted
1890 */
buzbee67bf8852011-08-17 17:51:35 -07001891 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1892 }
buzbeecefd1872011-09-09 09:59:52 -07001893 if (!skipOverflowCheck) {
1894 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001895 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001896 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1897 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001898 genRegCopy(cUnit, rSP, rLR); // Establish stack
1899 } else {
1900 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001901 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001902 }
buzbee67bf8852011-08-17 17:51:35 -07001903 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1904 flushIns(cUnit);
1905 oatFreeTemp(cUnit, r0);
1906 oatFreeTemp(cUnit, r1);
1907 oatFreeTemp(cUnit, r2);
1908 oatFreeTemp(cUnit, r3);
1909 } else if (bb->blockType == kExitBlock) {
1910 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07001911 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07001912 /* Need to restore any FP callee saves? */
1913 if (cUnit->numFPSpills) {
1914 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1915 }
1916 if (cUnit->coreSpillMask & (1 << rLR)) {
1917 /* Unspill rLR to rPC */
1918 cUnit->coreSpillMask &= ~(1 << rLR);
1919 cUnit->coreSpillMask |= (1 << rPC);
1920 }
1921 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1922 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1923 /* We didn't pop to rPC, so must do a bv rLR */
1924 newLIR1(cUnit, kThumbBx, rLR);
1925 }
1926 }
1927
1928 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1929
1930 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07001931 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1932 oatClobberAllRegs(cUnit);
1933 }
buzbee67bf8852011-08-17 17:51:35 -07001934
1935 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1936 oatResetDefTracking(cUnit);
1937 }
1938
1939 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1940 handleExtendedMethodMIR(cUnit, mir);
1941 continue;
1942 }
1943
1944 cUnit->currentDalvikOffset = mir->offset;
1945
1946 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1947 InstructionFormat dalvikFormat =
1948 dexGetFormatFromOpcode(dalvikOpcode);
1949
1950 ArmLIR* boundaryLIR;
1951
1952 /* Mark the beginning of a Dalvik instruction for line tracking */
1953 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1954 (int) oatGetDalvikDisassembly(
1955 &mir->dalvikInsn, ""));
1956 /* Remember the first LIR for this block */
1957 if (headLIR == NULL) {
1958 headLIR = boundaryLIR;
1959 /* Set the first boundaryLIR as a scheduling barrier */
1960 headLIR->defMask = ENCODE_ALL;
1961 }
1962
1963 /* Don't generate the SSA annotation unless verbose mode is on */
1964 if (cUnit->printMe && mir->ssaRep) {
1965 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1966 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1967 }
1968
1969 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1970
1971 if (notHandled) {
1972 char buf[100];
1973 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1974 mir->offset,
1975 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1976 dalvikFormat);
1977 LOG(FATAL) << buf;
1978 }
1979 }
1980
1981 if (headLIR) {
1982 /*
1983 * Eliminate redundant loads/stores and delay stores into later
1984 * slots
1985 */
1986 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1987 cUnit->lastLIRInsn);
1988
1989 /*
1990 * Generate an unconditional branch to the fallthrough block.
1991 */
1992 if (bb->fallThrough) {
1993 genUnconditionalBranch(cUnit,
1994 &labelList[bb->fallThrough->id]);
1995 }
1996 }
1997 return false;
1998}
1999
2000/*
2001 * Nop any unconditional branches that go to the next instruction.
2002 * Note: new redundant branches may be inserted later, and we'll
2003 * use a check in final instruction assembly to nop those out.
2004 */
2005void removeRedundantBranches(CompilationUnit* cUnit)
2006{
2007 ArmLIR* thisLIR;
2008
2009 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2010 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2011 thisLIR = NEXT_LIR(thisLIR)) {
2012
2013 /* Branch to the next instruction */
2014 if ((thisLIR->opcode == kThumbBUncond) ||
2015 (thisLIR->opcode == kThumb2BUncond)) {
2016 ArmLIR* nextLIR = thisLIR;
2017
2018 while (true) {
2019 nextLIR = NEXT_LIR(nextLIR);
2020
2021 /*
2022 * Is the branch target the next instruction?
2023 */
2024 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2025 thisLIR->flags.isNop = true;
2026 break;
2027 }
2028
2029 /*
2030 * Found real useful stuff between the branch and the target.
2031 * Need to explicitly check the lastLIRInsn here because it
2032 * might be the last real instruction.
2033 */
2034 if (!isPseudoOpcode(nextLIR->opcode) ||
2035 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2036 break;
2037 }
2038 }
2039 }
2040}
2041
buzbeeed3e9302011-09-23 17:34:19 -07002042STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002043{
2044 ArmLIR** suspendLabel =
2045 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2046 int numElems = cUnit->suspendLaunchpads.numUsed;
2047
2048 for (int i = 0; i < numElems; i++) {
2049 /* TUNING: move suspend count load into helper */
2050 ArmLIR* lab = suspendLabel[i];
2051 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2052 cUnit->currentDalvikOffset = lab->operands[1];
2053 oatAppendLIR(cUnit, (LIR *)lab);
2054 loadWordDisp(cUnit, rSELF,
2055 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2056 loadWordDisp(cUnit, rSELF,
2057 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2058 opReg(cUnit, kOpBlx, rLR);
2059 genUnconditionalBranch(cUnit, resumeLab);
2060 }
2061}
2062
buzbeeed3e9302011-09-23 17:34:19 -07002063STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002064{
2065 ArmLIR** throwLabel =
2066 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2067 int numElems = cUnit->throwLaunchpads.numUsed;
2068 int i;
2069
2070 for (i = 0; i < numElems; i++) {
2071 ArmLIR* lab = throwLabel[i];
2072 cUnit->currentDalvikOffset = lab->operands[1];
2073 oatAppendLIR(cUnit, (LIR *)lab);
2074 int funcOffset = 0;
2075 int v1 = lab->operands[2];
2076 int v2 = lab->operands[3];
2077 switch(lab->operands[0]) {
2078 case kArmThrowNullPointer:
2079 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2080 break;
2081 case kArmThrowArrayBounds:
2082 if (v2 != r0) {
2083 genRegCopy(cUnit, r0, v1);
2084 genRegCopy(cUnit, r1, v2);
2085 } else {
2086 if (v1 == r1) {
2087 genRegCopy(cUnit, r12, v1);
2088 genRegCopy(cUnit, r1, v2);
2089 genRegCopy(cUnit, r0, r12);
2090 } else {
2091 genRegCopy(cUnit, r1, v2);
2092 genRegCopy(cUnit, r0, v1);
2093 }
2094 }
2095 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2096 break;
2097 case kArmThrowDivZero:
2098 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2099 break;
2100 case kArmThrowVerificationError:
2101 loadConstant(cUnit, r0, v1);
2102 loadConstant(cUnit, r1, v2);
2103 funcOffset =
2104 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2105 break;
2106 case kArmThrowNegArraySize:
2107 genRegCopy(cUnit, r0, v1);
2108 funcOffset =
2109 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2110 break;
2111 case kArmThrowInternalError:
2112 genRegCopy(cUnit, r0, v1);
2113 funcOffset =
2114 OFFSETOF_MEMBER(Thread, pThrowInternalErrorFromCode);
2115 break;
2116 case kArmThrowRuntimeException:
2117 genRegCopy(cUnit, r0, v1);
2118 funcOffset =
2119 OFFSETOF_MEMBER(Thread, pThrowRuntimeExceptionFromCode);
2120 break;
2121 case kArmThrowNoSuchMethod:
2122 genRegCopy(cUnit, r0, v1);
2123 funcOffset =
2124 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2125 break;
buzbeeec5adf32011-09-11 15:25:43 -07002126 case kArmThrowStackOverflow:
2127 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002128 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002129 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002130 opRegImm(cUnit, kOpAdd, rSP,
2131 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002132 break;
buzbee5ade1d22011-09-09 14:44:52 -07002133 default:
2134 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2135 }
2136 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002137 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002138 }
2139}
2140
buzbee67bf8852011-08-17 17:51:35 -07002141void oatMethodMIR2LIR(CompilationUnit* cUnit)
2142{
2143 /* Used to hold the labels of each block */
2144 cUnit->blockLabelList =
2145 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2146
2147 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2148 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002149 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002150
2151 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002152
2153 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002154}
2155
2156/* Common initialization routine for an architecture family */
2157bool oatArchInit()
2158{
2159 int i;
2160
2161 for (i = 0; i < kArmLast; i++) {
2162 if (EncodingMap[i].opcode != i) {
2163 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2164 " is wrong: expecting " << i << ", seeing " <<
2165 (int)EncodingMap[i].opcode;
2166 }
2167 }
2168
2169 return oatArchVariantInit();
2170}
2171
2172/* Needed by the Assembler */
2173void oatSetupResourceMasks(ArmLIR* lir)
2174{
2175 setupResourceMasks(lir);
2176}
2177
2178/* Needed by the ld/st optmizatons */
2179ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2180{
2181 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2182}
2183
2184/* Needed by the register allocator */
2185ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2186{
2187 return genRegCopy(cUnit, rDest, rSrc);
2188}
2189
2190/* Needed by the register allocator */
2191void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2192 int srcLo, int srcHi)
2193{
2194 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2195}
2196
2197void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2198 int displacement, int rSrc, OpSize size)
2199{
2200 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2201}
2202
2203void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2204 int displacement, int rSrcLo, int rSrcHi)
2205{
2206 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2207}