blob: cfeb16aa4571fd0bebbdac449124be835269737f [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughes1240dad2011-09-09 16:24:50 -070017#define DISPLAY_MISSING_TARGETS 1
18
buzbeeed3e9302011-09-23 17:34:19 -070019STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
buzbee67bf8852011-08-17 17:51:35 -070020 INVALID_REG, INVALID_SREG, 0,
21 kLocDalvikFrame, INVALID_REG, INVALID_REG,
22 INVALID_OFFSET};
buzbee6181f792011-09-29 11:14:04 -070023
24/* Mark register usage state and return long retloc */
25STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
26{
27 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
28 oatLockTemp(cUnit, res.lowReg);
29 oatLockTemp(cUnit, res.highReg);
30 oatMarkPair(cUnit, res.lowReg, res.highReg);
31 return res;
32}
33
34STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
35{
36 RegLocation res = LOC_DALVIK_RETURN_VAL;
37 oatLockTemp(cUnit, res.lowReg);
38 return res;
39}
buzbee67bf8852011-08-17 17:51:35 -070040
buzbeedfd3d702011-08-28 12:56:51 -070041/*
42 * Let helper function take care of everything. Will call
43 * Array::AllocFromCode(type_idx, method, count);
44 * Note: AllocFromCode will handle checks for errNegativeArraySize.
45 */
buzbeeed3e9302011-09-23 17:34:19 -070046STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -070047 RegLocation rlSrc)
48{
buzbeedfd3d702011-08-28 12:56:51 -070049 oatFlushAllRegs(cUnit); /* Everything to home location */
50 loadWordDisp(cUnit, rSELF,
Ian Rogersb886da82011-09-23 16:27:54 -070051 OFFSETOF_MEMBER(Thread, pArrayAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070052 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
53 loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
54 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070055 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070056 RegLocation rlResult = oatGetReturn(cUnit);
57 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070058}
59
60/*
61 * Similar to genNewArray, but with post-allocation initialization.
62 * Verifier guarantees we're dealing with an array class. Current
63 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
64 * Current code also throws internal unimp if not 'L', '[' or 'I'.
65 */
buzbeeed3e9302011-09-23 17:34:19 -070066STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070067{
68 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070069 int elems = dInsn->vA;
70 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070071 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070072 loadWordDisp(cUnit, rSELF,
Ian Rogersb886da82011-09-23 16:27:54 -070073 OFFSETOF_MEMBER(Thread, pCheckAndArrayAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070074 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
75 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
76 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070077 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070078 /*
buzbeedfd3d702011-08-28 12:56:51 -070079 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
80 * return region. Because AllocFromCode placed the new array
81 * in r0, we'll just lock it into place. When debugger support is
82 * added, it may be necessary to additionally copy all return
83 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070084 */
buzbee67bf8852011-08-17 17:51:35 -070085 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070086
buzbee67bf8852011-08-17 17:51:35 -070087 // Having a range of 0 is legal
88 if (isRange && (dInsn->vA > 0)) {
89 /*
90 * Bit of ugliness here. We're going generate a mem copy loop
91 * on the register range, but it is possible that some regs
92 * in the range have been promoted. This is unlikely, but
93 * before generating the copy, we'll just force a flush
94 * of any regs in the source range that have been promoted to
95 * home location.
96 */
97 for (unsigned int i = 0; i < dInsn->vA; i++) {
98 RegLocation loc = oatUpdateLoc(cUnit,
99 oatGetSrc(cUnit, mir, i));
100 if (loc.location == kLocPhysReg) {
101 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
102 }
103 }
104 /*
105 * TUNING note: generated code here could be much improved, but
106 * this is an uncommon operation and isn't especially performance
107 * critical.
108 */
109 int rSrc = oatAllocTemp(cUnit);
110 int rDst = oatAllocTemp(cUnit);
111 int rIdx = oatAllocTemp(cUnit);
112 int rVal = rLR; // Using a lot of temps, rLR is known free here
113 // Set up source pointer
114 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
115 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
116 // Set up the target pointer
117 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700118 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700119 // Set up the loop counter (known to be > 0)
120 loadConstant(cUnit, rIdx, dInsn->vA);
121 // Generate the copy loop. Going backwards for convenience
122 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
123 target->defMask = ENCODE_ALL;
124 // Copy next element
125 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
126 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
127 // Use setflags encoding here
128 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
129 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
130 branch->generic.target = (LIR*)target;
131 } else if (!isRange) {
132 // TUNING: interleave
133 for (unsigned int i = 0; i < dInsn->vA; i++) {
134 RegLocation rlArg = loadValue(cUnit,
135 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700136 storeBaseDisp(cUnit, r0,
137 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700138 i * 4, rlArg.lowReg, kWord);
139 // If the loadValue caused a temp to be allocated, free it
140 if (oatIsTemp(cUnit, rlArg.lowReg)) {
141 oatFreeTemp(cUnit, rlArg.lowReg);
142 }
143 }
144 }
145}
146
Brian Carlstrom845490b2011-09-19 15:56:53 -0700147Field* FindFieldWithResolvedStaticStorage(const Method* method,
148 const uint32_t fieldIdx,
149 uint32_t& resolvedTypeIdx) {
150 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
151 Field* field = class_linker->ResolveField(fieldIdx, method, true);
152 if (field == NULL) {
153 return NULL;
154 }
155 const art::DexFile& dex_file = class_linker->
156 FindDexFile(method->GetDeclaringClass()->GetDexCache());
157 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
158 int type_idx = field_id.class_idx_;
159 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
160 // Check if storage class is the same as class referred to by type idx.
161 // They may not be if the FieldId refers a subclass, but storage is in super
162 if (field->GetDeclaringClass() == klass) {
163 resolvedTypeIdx = type_idx;
164 return field;
165 }
166 // See if we can find a dex reference for the storage class.
167 // we may not if the dex file never references the super class,
168 // but usually it will.
169 std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
170 for (size_t type_idx = 0; type_idx < dex_file.NumTypeIds(); type_idx++) {
171 const art::DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
172 if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
173 resolvedTypeIdx = type_idx;
174 return field;
175 }
176 }
177 return NULL; // resort to slow path
178}
179
buzbeeed3e9302011-09-23 17:34:19 -0700180STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700181{
buzbeee1931742011-08-28 21:15:53 -0700182 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
183 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700184 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700185 uint32_t typeIdx;
186 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700187 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700188 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700189 // Slow path
buzbee34cd9e52011-09-08 14:31:52 -0700190 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
191 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700192 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
193 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700194 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
195 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
196 loadCurrMethodDirect(cUnit, r1);
197 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700198 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700199 } else {
buzbee1da522d2011-09-04 11:22:20 -0700200 // fast path
201 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700202 // Using fixed register to sync with slow path
203 int rMethod = r1;
204 oatLockTemp(cUnit, rMethod);
205 loadCurrMethodDirect(cUnit, rMethod);
206 int rBase = r0;
207 oatLockTemp(cUnit, rBase);
208 loadWordDisp(cUnit, rMethod,
209 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
210 rBase);
211 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
212 sizeof(int32_t*)* typeIdx, rBase);
213 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700214 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700215 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
216 loadWordDisp(cUnit, rSELF,
217 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
218 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700219 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700220 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
221 skipTarget->defMask = ENCODE_ALL;
222 branchOver->generic.target = (LIR*)skipTarget;
223 rlSrc = oatGetSrc(cUnit, mir, 0);
224 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
225 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700226#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700227 if (field->IsVolatile()) {
228 oatGenMemBarrier(cUnit, kSY);
229 }
buzbee67bf8852011-08-17 17:51:35 -0700230#endif
buzbee1da522d2011-09-04 11:22:20 -0700231 if (isObject) {
232 markGCCard(cUnit, rlSrc.lowReg, rBase);
233 }
234 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700235 }
buzbee67bf8852011-08-17 17:51:35 -0700236}
237
buzbeeed3e9302011-09-23 17:34:19 -0700238STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700239{
buzbee1da522d2011-09-04 11:22:20 -0700240 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700241 uint32_t typeIdx;
242 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700243 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700244 if (SLOW_FIELD_PATH || field == NULL) {
245 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
246 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700247 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700248 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
249 loadCurrMethodDirect(cUnit, r1);
250 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700251 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700252 } else {
buzbee1da522d2011-09-04 11:22:20 -0700253 // fast path
254 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700255 // Using fixed register to sync with slow path
256 int rMethod = r1;
257 oatLockTemp(cUnit, rMethod);
258 loadCurrMethodDirect(cUnit, r1);
259 int rBase = r0;
260 oatLockTemp(cUnit, rBase);
261 loadWordDisp(cUnit, rMethod,
262 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
263 rBase);
264 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
265 sizeof(int32_t*)* typeIdx, rBase);
266 // TUNING: fast path should fall through
267 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
268 loadWordDisp(cUnit, rSELF,
269 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
270 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700271 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700272 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
273 skipTarget->defMask = ENCODE_ALL;
274 branchOver->generic.target = (LIR*)skipTarget;
275 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
276 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
277 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
278 rlSrc.highReg);
279#if ANDROID_SMP != 0
280 if (field->IsVolatile()) {
281 oatGenMemBarrier(cUnit, kSY);
282 }
buzbeec143c552011-08-20 17:38:58 -0700283#endif
buzbee1da522d2011-09-04 11:22:20 -0700284 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700285 }
buzbee67bf8852011-08-17 17:51:35 -0700286}
287
288
buzbeeed3e9302011-09-23 17:34:19 -0700289STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700290 RegLocation rlResult, RegLocation rlDest)
291{
buzbee1da522d2011-09-04 11:22:20 -0700292 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700293 uint32_t typeIdx;
294 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700295 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700296 if (SLOW_FIELD_PATH || field == NULL) {
297 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
298 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700299 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700300 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
301 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700302 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700303 RegLocation rlResult = oatGetReturnWide(cUnit);
304 storeValueWide(cUnit, rlDest, rlResult);
305 } else {
buzbee1da522d2011-09-04 11:22:20 -0700306 // Fast path
307 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700308 // Using fixed register to sync with slow path
309 int rMethod = r1;
310 oatLockTemp(cUnit, rMethod);
311 loadCurrMethodDirect(cUnit, rMethod);
312 int rBase = r0;
313 oatLockTemp(cUnit, rBase);
314 loadWordDisp(cUnit, rMethod,
315 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
316 rBase);
317 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
318 sizeof(int32_t*)* typeIdx, rBase);
319 // TUNING: fast path should fall through
320 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
321 loadWordDisp(cUnit, rSELF,
322 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
323 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700324 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700325 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
326 skipTarget->defMask = ENCODE_ALL;
327 branchOver->generic.target = (LIR*)skipTarget;
328 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
329 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
330#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700331 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700332 oatGenMemBarrier(cUnit, kSY);
333 }
buzbeec143c552011-08-20 17:38:58 -0700334#endif
buzbee1da522d2011-09-04 11:22:20 -0700335 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
336 rlResult.highReg, INVALID_SREG);
337 oatFreeTemp(cUnit, rBase);
338 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700339 }
buzbee67bf8852011-08-17 17:51:35 -0700340}
341
buzbeeed3e9302011-09-23 17:34:19 -0700342STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700343 RegLocation rlResult, RegLocation rlDest)
344{
buzbee1da522d2011-09-04 11:22:20 -0700345 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700346 uint32_t typeIdx;
347 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700348 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
349 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700350 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700351 if (SLOW_FIELD_PATH || field == NULL) {
352 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
353 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700354 // Slow path
355 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
356 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700357 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
358 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
359 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700360 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700361 RegLocation rlResult = oatGetReturn(cUnit);
362 storeValue(cUnit, rlDest, rlResult);
363 } else {
buzbee1da522d2011-09-04 11:22:20 -0700364 // Fast path
365 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700366 // Using fixed register to sync with slow path
367 int rMethod = r1;
368 oatLockTemp(cUnit, rMethod);
369 loadCurrMethodDirect(cUnit, rMethod);
370 int rBase = r0;
371 oatLockTemp(cUnit, rBase);
372 loadWordDisp(cUnit, rMethod,
373 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
374 rBase);
375 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
376 sizeof(int32_t*)* typeIdx, rBase);
377 // TUNING: fast path should fall through
378 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
379 loadWordDisp(cUnit, rSELF,
380 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
381 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700382 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700383 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
384 skipTarget->defMask = ENCODE_ALL;
385 branchOver->generic.target = (LIR*)skipTarget;
386 rlDest = oatGetDest(cUnit, mir, 0);
387 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700388#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700389 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700390 oatGenMemBarrier(cUnit, kSY);
391 }
buzbee67bf8852011-08-17 17:51:35 -0700392#endif
buzbee1da522d2011-09-04 11:22:20 -0700393 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
394 oatFreeTemp(cUnit, rBase);
395 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700396 }
buzbee67bf8852011-08-17 17:51:35 -0700397}
398
buzbee561227c2011-09-02 15:28:19 -0700399typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
400 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700401
402/*
403 * Bit of a hack here - in leiu of a real scheduling pass,
404 * emit the next instruction in static & direct invoke sequences.
405 */
buzbeeed3e9302011-09-23 17:34:19 -0700406STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700407 DecodedInstruction* dInsn, int state,
408 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700409{
buzbee561227c2011-09-02 15:28:19 -0700410 DCHECK(rollback == NULL);
411 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700412 switch(state) {
413 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700414 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700415 break;
buzbee561227c2011-09-02 15:28:19 -0700416 case 1: // Get method->code_and_direct_methods_
417 loadWordDisp(cUnit, r0,
418 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
419 r0);
buzbee67bf8852011-08-17 17:51:35 -0700420 break;
buzbee561227c2011-09-02 15:28:19 -0700421 case 2: // Grab target method* and target code_
422 loadWordDisp(cUnit, r0,
423 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
424 loadWordDisp(cUnit, r0,
425 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700426 break;
427 default:
428 return -1;
429 }
430 return state + 1;
431}
432
buzbee67bf8852011-08-17 17:51:35 -0700433/*
434 * Bit of a hack here - in leiu of a real scheduling pass,
435 * emit the next instruction in a virtual invoke sequence.
436 * We can use rLR as a temp prior to target address loading
437 * Note also that we'll load the first argument ("this") into
438 * r1 here rather than the standard loadArgRegs.
439 */
buzbeeed3e9302011-09-23 17:34:19 -0700440STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700441 DecodedInstruction* dInsn, int state,
442 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700443{
buzbee561227c2011-09-02 15:28:19 -0700444 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700445 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700446 /*
447 * This is the fast path in which the target virtual method is
448 * fully resolved at compile time.
449 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700450 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
451 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -0700452 CHECK(baseMethod != NULL);
453 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700454 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700455 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700456 rlArg = oatGetSrc(cUnit, mir, 0);
457 loadValueDirectFixed(cUnit, rlArg, r1);
458 break;
buzbee561227c2011-09-02 15:28:19 -0700459 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700460 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700461 // get this->klass_ [use r1, set rLR]
462 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700463 break;
buzbee561227c2011-09-02 15:28:19 -0700464 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
465 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700466 break;
buzbee561227c2011-09-02 15:28:19 -0700467 case 3: // Get target method [use rLR, set r0]
468 loadWordDisp(cUnit, rLR, (target_idx * 4) +
469 art::Array::DataOffset().Int32Value(), r0);
470 break;
471 case 4: // Get the target compiled code address [uses r0, sets rLR]
472 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700473 break;
474 default:
475 return -1;
476 }
477 return state + 1;
478}
479
buzbeeed3e9302011-09-23 17:34:19 -0700480STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700481 DecodedInstruction* dInsn, int state,
482 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700483{
buzbeeed3e9302011-09-23 17:34:19 -0700484 DCHECK(rollback == NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700485 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700486 ArmLIR* skipBranch;
487 ArmLIR* skipTarget;
488 /*
489 * This handles the case in which the base method is not fully
490 * resolved at compile time. We must generate code to test
491 * for resolution a run time, bail to the slow path if not to
492 * fill in all the tables. In the latter case, we'll restart at
493 * at the beginning of the sequence.
494 */
buzbee7b1b86d2011-08-26 18:59:10 -0700495 switch(state) {
496 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700497 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700498 break;
buzbee561227c2011-09-02 15:28:19 -0700499 case 1: // Get method->dex_cache_resolved_methods_
500 loadWordDisp(cUnit, r0,
501 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700502 break;
buzbee561227c2011-09-02 15:28:19 -0700503 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
504 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
505 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700506 break;
buzbee561227c2011-09-02 15:28:19 -0700507 case 3: // Resolved?
508 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
509 // Slowest path, bail to helper, rollback and retry
510 loadWordDisp(cUnit, rSELF,
511 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
512 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700513 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700514 genUnconditionalBranch(cUnit, rollback);
515 // Resume normal slow path
516 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
517 skipTarget->defMask = ENCODE_ALL;
518 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700519 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700520 loadBaseDisp(cUnit, mir, rLR,
521 Method::GetMethodIndexOffset().Int32Value(), r0,
522 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700523 // Load "this" [set r1]
524 rlArg = oatGetSrc(cUnit, mir, 0);
525 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700526 break;
527 case 4:
528 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700529 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700530 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700531 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700532 break;
buzbee561227c2011-09-02 15:28:19 -0700533 case 5:
534 // get this->klass_->vtable_ [usr rLR, set rLR]
535 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700536 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700537 // In load shadow fold vtable_ object header size into method_index_
538 opRegImm(cUnit, kOpAdd, r0,
539 art::Array::DataOffset().Int32Value() / 4);
540 // Get target Method*
541 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
542 break;
543 case 6: // Get the target compiled code address [uses r0, sets rLR]
544 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700545 break;
546 default:
547 return -1;
548 }
549 return state + 1;
550}
551
buzbeeed3e9302011-09-23 17:34:19 -0700552STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700553 DecodedInstruction* dInsn, int callState,
554 NextCallInsn nextCallInsn, ArmLIR* rollback,
555 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700556{
buzbeec0ecd652011-09-25 18:11:54 -0700557 int nextReg = r1;
558 int nextArg = 0;
559 if (skipThis) {
560 nextReg++;
561 nextArg++;
562 }
563 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
564 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
565 rlArg = oatUpdateRawLoc(cUnit, rlArg);
566 if (rlArg.wide && (nextReg <= r2)) {
567 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
568 nextReg++;
569 nextArg++;
570 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700571 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700572 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700573 }
buzbeec0ecd652011-09-25 18:11:54 -0700574 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700575 }
576 return callState;
577}
578
buzbee4a3164f2011-09-03 11:25:10 -0700579// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700580STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700581 DecodedInstruction* dInsn, int state,
582 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700583{
buzbee67bf8852011-08-17 17:51:35 -0700584 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700585 case 0: // Load trampoline target
586 loadWordDisp(cUnit, rSELF,
587 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
588 rLR);
589 // Load r0 with method index
590 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700591 break;
buzbee67bf8852011-08-17 17:51:35 -0700592 default:
593 return -1;
594 }
595 return state + 1;
596}
597
buzbee67bf8852011-08-17 17:51:35 -0700598/*
599 * Interleave launch code for INVOKE_SUPER. See comments
600 * for nextVCallIns.
601 */
buzbeeed3e9302011-09-23 17:34:19 -0700602STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700603 DecodedInstruction* dInsn, int state,
604 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700605{
buzbee4a3164f2011-09-03 11:25:10 -0700606 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700607 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700608 /*
609 * This is the fast path in which the target virtual method is
610 * fully resolved at compile time. Note also that this path assumes
611 * that the check to verify that the target method index falls
612 * within the size of the super's vtable has been done at compile-time.
613 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700614 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
615 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700616 CHECK(baseMethod != NULL);
617 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
618 CHECK(superClass != NULL);
619 int32_t target_idx = baseMethod->GetMethodIndex();
620 CHECK(superClass->GetVTable()->GetLength() > target_idx);
621 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
622 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700623 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700624 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700625 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700626 // Load "this" [set r1]
627 rlArg = oatGetSrc(cUnit, mir, 0);
628 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700629 // Get method->declaring_class_ [use r0, set rLR]
630 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
631 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700632 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700633 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700634 break;
635 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
636 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
637 rLR);
638 break;
639 case 2: // Get ...->super_class_->vtable [u/s rLR]
640 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
641 break;
642 case 3: // Get target method [use rLR, set r0]
643 loadWordDisp(cUnit, rLR, (target_idx * 4) +
644 art::Array::DataOffset().Int32Value(), r0);
645 break;
646 case 4: // Get the target compiled code address [uses r0, sets rLR]
647 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
648 break;
buzbee67bf8852011-08-17 17:51:35 -0700649 default:
650 return -1;
651 }
buzbee4a3164f2011-09-03 11:25:10 -0700652 return state + 1;
653}
654
655/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700656STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700657 DecodedInstruction* dInsn, int state,
658 ArmLIR* rollback)
659{
buzbeeed3e9302011-09-23 17:34:19 -0700660 DCHECK(rollback == NULL);
buzbee4a3164f2011-09-03 11:25:10 -0700661 RegLocation rlArg;
662 ArmLIR* skipBranch;
663 ArmLIR* skipTarget;
664 int tReg;
665 /*
666 * This handles the case in which the base method is not fully
667 * resolved at compile time. We must generate code to test
668 * for resolution a run time, bail to the slow path if not to
669 * fill in all the tables. In the latter case, we'll restart at
670 * at the beginning of the sequence.
671 */
672 switch(state) {
673 case 0: // Get the current Method* [sets r0]
674 loadCurrMethodDirect(cUnit, r0);
675 break;
676 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
677 loadWordDisp(cUnit, r0,
678 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
679 break;
680 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
681 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
682 art::Array::DataOffset().Int32Value(), rLR);
683 break;
684 case 3: // Resolved?
685 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
686 // Slowest path, bail to helper, rollback and retry
687 loadWordDisp(cUnit, rSELF,
688 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
689 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700690 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700691 genUnconditionalBranch(cUnit, rollback);
692 // Resume normal slow path
693 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
694 skipTarget->defMask = ENCODE_ALL;
695 skipBranch->generic.target = (LIR*)skipTarget;
696 // Get base_method->method_index [usr rLR, set rLR]
697 loadBaseDisp(cUnit, mir, rLR,
698 Method::GetMethodIndexOffset().Int32Value(), rLR,
699 kUnsignedHalf, INVALID_SREG);
700 // Load "this" [set r1]
701 rlArg = oatGetSrc(cUnit, mir, 0);
702 loadValueDirectFixed(cUnit, rlArg, r1);
703 // Load curMethod->declaring_class_ [uses r0, sets r0]
704 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
705 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700706 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700707 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700708 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700709 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
710 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700711 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700712 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700713 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700714 // Range check, throw NSM on failure
715 tReg = oatAllocTemp(cUnit);
716 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
717 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700718 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
719 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700720 oatFreeTemp(cUnit, tReg);
721 }
buzbee6a0f7f52011-09-05 16:14:20 -0700722 // Adjust vtable_ base past object header
723 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700724 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700725 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700726 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700727 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700728 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
729 break;
730 default:
731 return -1;
732 }
buzbee67bf8852011-08-17 17:51:35 -0700733 return state + 1;
734}
735
736/*
737 * Load up to 5 arguments, the first three of which will be in
738 * r1 .. r3. On entry r0 contains the current method pointer,
739 * and as part of the load sequence, it must be replaced with
740 * the target method pointer. Note, this may also be called
741 * for "range" variants if the number of arguments is 5 or fewer.
742 */
buzbeeed3e9302011-09-23 17:34:19 -0700743STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700744 DecodedInstruction* dInsn, int callState,
745 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700746 NextCallInsn nextCallInsn, ArmLIR* rollback,
747 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700748{
749 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700750
751 /* If no arguments, just return */
752 if (dInsn->vA == 0)
753 return callState;
754
buzbee561227c2011-09-02 15:28:19 -0700755 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700756
buzbeec0ecd652011-09-25 18:11:54 -0700757 DCHECK_LE(dInsn->vA, 5U);
758 if (dInsn->vA > 3) {
759 uint32_t nextUse = 3;
760 //Detect special case of wide arg spanning arg3/arg4
761 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
762 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
763 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
764 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
765 rlUse2.wide) {
766 int reg;
767 // Wide spans, we need the 2nd half of uses[2].
768 rlArg = oatUpdateLocWide(cUnit, rlUse2);
769 if (rlArg.location == kLocPhysReg) {
770 reg = rlArg.highReg;
771 } else {
772 // r2 & r3 can safely be used here
773 reg = r3;
774 loadWordDisp(cUnit, rSP, rlArg.spOffset + 4, reg);
775 callState = nextCallInsn(cUnit, mir, dInsn, callState,
776 rollback);
777 }
778 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
779 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
780 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
781 nextUse++;
782 }
783 // Loop through the rest
784 while (nextUse < dInsn->vA) {
785 int lowReg;
786 int highReg;
787 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
788 rlArg = oatUpdateRawLoc(cUnit, rlArg);
789 if (rlArg.location == kLocPhysReg) {
790 lowReg = rlArg.lowReg;
791 highReg = rlArg.highReg;
792 } else {
793 lowReg = r2;
794 highReg = r3;
795 if (rlArg.wide) {
796 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
797 } else {
798 loadValueDirectFixed(cUnit, rlArg, lowReg);
799 }
800 callState = nextCallInsn(cUnit, mir, dInsn, callState,
801 rollback);
802 }
803 int outsOffset = (nextUse + 1) * 4;
804 if (rlArg.wide) {
805 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
806 nextUse += 2;
807 } else {
808 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
809 nextUse++;
810 }
buzbee561227c2011-09-02 15:28:19 -0700811 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700812 }
buzbee67bf8852011-08-17 17:51:35 -0700813 }
814
buzbeec0ecd652011-09-25 18:11:54 -0700815 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
816 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700817
buzbee6a0f7f52011-09-05 16:14:20 -0700818 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700819 // Load direct & need a "this" null check?
820 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700821 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700822 }
823 return callState;
824}
825
826/*
827 * May have 0+ arguments (also used for jumbo). Note that
828 * source virtual registers may be in physical registers, so may
829 * need to be flushed to home location before copying. This
830 * applies to arg3 and above (see below).
831 *
832 * Two general strategies:
833 * If < 20 arguments
834 * Pass args 3-18 using vldm/vstm block copy
835 * Pass arg0, arg1 & arg2 in r1-r3
836 * If 20+ arguments
837 * Pass args arg19+ using memcpy block copy
838 * Pass arg0, arg1 & arg2 in r1-r3
839 *
840 */
buzbeeed3e9302011-09-23 17:34:19 -0700841STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700842 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700843 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700844 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700845{
846 int firstArg = dInsn->vC;
847 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700848
buzbee67bf8852011-08-17 17:51:35 -0700849 // If we can treat it as non-range (Jumbo ops will use range form)
850 if (numArgs <= 5)
851 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700852 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700853 /*
854 * Make sure range list doesn't span the break between in normal
855 * Dalvik vRegs and the ins.
856 */
buzbee1b4c8592011-08-31 10:43:51 -0700857 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700858 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700859 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
860 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700861 }
862
863 /*
864 * First load the non-register arguments. Both forms expect all
865 * of the source arguments to be in their home frame location, so
866 * scan the sReg names and flush any that have been promoted to
867 * frame backing storage.
868 */
869 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700870 for (int nextArg = 0; nextArg < numArgs;) {
871 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700872 if (loc.wide) {
873 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700874 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee1b4c8592011-08-31 10:43:51 -0700875 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
876 loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700877 }
buzbeec0ecd652011-09-25 18:11:54 -0700878 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700879 } else {
880 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700881 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee1b4c8592011-08-31 10:43:51 -0700882 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700883 }
buzbeec0ecd652011-09-25 18:11:54 -0700884 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700885 }
886 }
887
888 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
889 int outsOffset = 4 /* Method* */ + (3 * 4);
890 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700891 // Generate memcpy
892 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
893 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700894 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
895 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700896 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700897 // Restore Method*
898 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700899 } else {
900 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700901 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700902 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700903 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700904 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
905 //TUNING: loosen barrier
906 ld->defMask = ENCODE_ALL;
907 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700908 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700909 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700910 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700911 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
912 setMemRefType(st, false /* isLoad */, kDalvikReg);
913 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700914 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700915 }
916
buzbeec0ecd652011-09-25 18:11:54 -0700917 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
918 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700919
buzbee561227c2011-09-02 15:28:19 -0700920 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700921 return callState;
922}
923
buzbee2a475e72011-09-07 17:19:17 -0700924#ifdef DISPLAY_MISSING_TARGETS
925// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700926STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700927{
928 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
929 loadWordDisp(cUnit, rSELF,
930 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
931 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
932 target->defMask = -1;
933 branchOver->generic.target = (LIR*)target;
934}
935#endif
936
buzbeeed3e9302011-09-23 17:34:19 -0700937STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700938 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700939{
940 DecodedInstruction* dInsn = &mir->dalvikInsn;
941 int callState = 0;
942 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700943 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700944 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700945 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700946
buzbee109bd6a2011-09-06 13:58:41 -0700947 // Explicit register usage
948 oatLockCallTemps(cUnit);
949
buzbee561227c2011-09-02 15:28:19 -0700950 if (range) {
951 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700952 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700953 } else {
954 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700955 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700956 }
buzbee67bf8852011-08-17 17:51:35 -0700957 // Finish up any of the call sequence not interleaved in arg loading
958 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700959 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700960 }
buzbee2a475e72011-09-07 17:19:17 -0700961#ifdef DISPLAY_MISSING_TARGETS
962 genShowTarget(cUnit);
963#endif
buzbeeec5adf32011-09-11 15:25:43 -0700964 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700965 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700966}
967
buzbee4a3164f2011-09-03 11:25:10 -0700968/*
969 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
970 * which will locate the target and continue on via a tail call.
971 */
buzbeeed3e9302011-09-23 17:34:19 -0700972STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -0700973{
974 DecodedInstruction* dInsn = &mir->dalvikInsn;
975 int callState = 0;
976 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -0700977 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -0700978
979 // Explicit register usage
980 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700981 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700982 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700983 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
984 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700985 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -0700986 false);
buzbee67bf8852011-08-17 17:51:35 -0700987 else
988 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -0700989 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -0700990 // Finish up any of the call sequence not interleaved in arg loading
991 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700992 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700993 }
buzbee2a475e72011-09-07 17:19:17 -0700994#ifdef DISPLAY_MISSING_TARGETS
995 genShowTarget(cUnit);
996#endif
buzbeeec5adf32011-09-11 15:25:43 -0700997 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700998 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700999}
1000
buzbeeed3e9302011-09-23 17:34:19 -07001001STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001002{
1003 DecodedInstruction* dInsn = &mir->dalvikInsn;
1004 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001005 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001006 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1007 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -07001008 NextCallInsn nextCallInsn;
1009 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001010 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001011
1012 // Explicit register usage
1013 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001014 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -07001015 fastPath = false;
1016 } else {
1017 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
1018 if (superClass == NULL) {
1019 fastPath = false;
1020 } else {
1021 int32_t target_idx = baseMethod->GetMethodIndex();
1022 if (superClass->GetVTable()->GetLength() <= target_idx) {
1023 fastPath = false;
1024 } else {
1025 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1026 }
1027 }
1028 }
1029 if (fastPath) {
1030 nextCallInsn = nextSuperCallInsn;
1031 rollback = NULL;
1032 } else {
1033 nextCallInsn = nextSuperCallInsnSP;
1034 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1035 rollback->defMask = -1;
1036 }
buzbee67bf8852011-08-17 17:51:35 -07001037 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001038 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001039 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001040 else
buzbeec0ecd652011-09-25 18:11:54 -07001041 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001042 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001043 // Finish up any of the call sequence not interleaved in arg loading
1044 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001045 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001046 }
buzbee2a475e72011-09-07 17:19:17 -07001047#ifdef DISPLAY_MISSING_TARGETS
1048 genShowTarget(cUnit);
1049#endif
buzbeeec5adf32011-09-11 15:25:43 -07001050 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001051 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001052}
1053
buzbeeed3e9302011-09-23 17:34:19 -07001054STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001055{
1056 DecodedInstruction* dInsn = &mir->dalvikInsn;
1057 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001058 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001059 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1060 Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -07001061 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001062 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee7b1b86d2011-08-26 18:59:10 -07001063
buzbee109bd6a2011-09-06 13:58:41 -07001064 // Explicit register usage
1065 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001066 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001067 // Slow path
1068 nextCallInsn = nextVCallInsnSP;
1069 // If we need a slow-path callout, we'll restart here
1070 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1071 rollback->defMask = -1;
1072 } else {
1073 // Fast path
1074 nextCallInsn = nextVCallInsn;
1075 rollback = NULL;
1076 }
buzbee67bf8852011-08-17 17:51:35 -07001077 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001078 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001079 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001080 else
buzbeec0ecd652011-09-25 18:11:54 -07001081 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001082 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001083 // Finish up any of the call sequence not interleaved in arg loading
1084 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001085 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001086 }
buzbee2a475e72011-09-07 17:19:17 -07001087#ifdef DISPLAY_MISSING_TARGETS
1088 genShowTarget(cUnit);
1089#endif
buzbeeec5adf32011-09-11 15:25:43 -07001090 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001091 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001092}
1093
buzbeeed3e9302011-09-23 17:34:19 -07001094STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001095 BasicBlock* bb, ArmLIR* labelList)
1096{
1097 bool res = false; // Assume success
1098 RegLocation rlSrc[3];
1099 RegLocation rlDest = badLoc;
1100 RegLocation rlResult = badLoc;
1101 Opcode opcode = mir->dalvikInsn.opcode;
1102
1103 /* Prep Src and Dest locations */
1104 int nextSreg = 0;
1105 int nextLoc = 0;
1106 int attrs = oatDataFlowAttributes[opcode];
1107 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1108 if (attrs & DF_UA) {
1109 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1110 nextSreg++;
1111 } else if (attrs & DF_UA_WIDE) {
1112 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1113 nextSreg + 1);
1114 nextSreg+= 2;
1115 }
1116 if (attrs & DF_UB) {
1117 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1118 nextSreg++;
1119 } else if (attrs & DF_UB_WIDE) {
1120 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1121 nextSreg + 1);
1122 nextSreg+= 2;
1123 }
1124 if (attrs & DF_UC) {
1125 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1126 } else if (attrs & DF_UC_WIDE) {
1127 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1128 nextSreg + 1);
1129 }
1130 if (attrs & DF_DA) {
1131 rlDest = oatGetDest(cUnit, mir, 0);
1132 } else if (attrs & DF_DA_WIDE) {
1133 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1134 }
1135
1136 switch(opcode) {
1137 case OP_NOP:
1138 break;
1139
1140 case OP_MOVE_EXCEPTION:
1141 int exOffset;
1142 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001143 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001144 resetReg = oatAllocTemp(cUnit);
1145 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1146 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1147 loadConstant(cUnit, resetReg, 0);
1148 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1149 storeValue(cUnit, rlDest, rlResult);
1150 break;
1151
1152 case OP_RETURN_VOID:
buzbeec0ecd652011-09-25 18:11:54 -07001153 genSuspendPoll(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001154 break;
1155
1156 case OP_RETURN:
1157 case OP_RETURN_OBJECT:
buzbeec1f45042011-09-21 16:03:19 -07001158 genSuspendPoll(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001159 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001160 break;
1161
1162 case OP_RETURN_WIDE:
buzbeec1f45042011-09-21 16:03:19 -07001163 genSuspendPoll(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001164 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001165 break;
1166
1167 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001168 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001169 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001170 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001171 break;
1172
1173 case OP_MOVE_RESULT:
1174 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001175 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001176 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001177 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001178 break;
1179
1180 case OP_MOVE:
1181 case OP_MOVE_OBJECT:
1182 case OP_MOVE_16:
1183 case OP_MOVE_OBJECT_16:
1184 case OP_MOVE_FROM16:
1185 case OP_MOVE_OBJECT_FROM16:
1186 storeValue(cUnit, rlDest, rlSrc[0]);
1187 break;
1188
1189 case OP_MOVE_WIDE:
1190 case OP_MOVE_WIDE_16:
1191 case OP_MOVE_WIDE_FROM16:
1192 storeValueWide(cUnit, rlDest, rlSrc[0]);
1193 break;
1194
1195 case OP_CONST:
1196 case OP_CONST_4:
1197 case OP_CONST_16:
1198 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1199 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1200 storeValue(cUnit, rlDest, rlResult);
1201 break;
1202
1203 case OP_CONST_HIGH16:
1204 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1205 loadConstantNoClobber(cUnit, rlResult.lowReg,
1206 mir->dalvikInsn.vB << 16);
1207 storeValue(cUnit, rlDest, rlResult);
1208 break;
1209
1210 case OP_CONST_WIDE_16:
1211 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001212 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1213 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1214 mir->dalvikInsn.vB,
1215 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001216 storeValueWide(cUnit, rlDest, rlResult);
1217 break;
1218
1219 case OP_CONST_WIDE:
1220 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1221 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001222 mir->dalvikInsn.vB_wide & 0xffffffff,
1223 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001224 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001225 break;
1226
1227 case OP_CONST_WIDE_HIGH16:
1228 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1229 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1230 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001231 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001232 break;
1233
1234 case OP_MONITOR_ENTER:
1235 genMonitorEnter(cUnit, mir, rlSrc[0]);
1236 break;
1237
1238 case OP_MONITOR_EXIT:
1239 genMonitorExit(cUnit, mir, rlSrc[0]);
1240 break;
1241
1242 case OP_CHECK_CAST:
1243 genCheckCast(cUnit, mir, rlSrc[0]);
1244 break;
1245
1246 case OP_INSTANCE_OF:
1247 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1248 break;
1249
1250 case OP_NEW_INSTANCE:
1251 genNewInstance(cUnit, mir, rlDest);
1252 break;
1253
1254 case OP_THROW:
1255 genThrow(cUnit, mir, rlSrc[0]);
1256 break;
1257
buzbee5ade1d22011-09-09 14:44:52 -07001258 case OP_THROW_VERIFICATION_ERROR:
1259 loadWordDisp(cUnit, rSELF,
1260 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1261 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1262 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001263 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001264 break;
1265
buzbee67bf8852011-08-17 17:51:35 -07001266 case OP_ARRAY_LENGTH:
1267 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001268 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001269 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001270 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001271 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1272 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1273 rlResult.lowReg);
1274 storeValue(cUnit, rlDest, rlResult);
1275 break;
1276
1277 case OP_CONST_STRING:
1278 case OP_CONST_STRING_JUMBO:
1279 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1280 break;
1281
1282 case OP_CONST_CLASS:
1283 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1284 break;
1285
1286 case OP_FILL_ARRAY_DATA:
1287 genFillArrayData(cUnit, mir, rlSrc[0]);
1288 break;
1289
1290 case OP_FILLED_NEW_ARRAY:
1291 genFilledNewArray(cUnit, mir, false /* not range */);
1292 break;
1293
1294 case OP_FILLED_NEW_ARRAY_RANGE:
1295 genFilledNewArray(cUnit, mir, true /* range */);
1296 break;
1297
1298 case OP_NEW_ARRAY:
1299 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1300 break;
1301
1302 case OP_GOTO:
1303 case OP_GOTO_16:
1304 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001305 if (bb->taken->startOffset <= mir->offset) {
1306 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001307 }
1308 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1309 break;
1310
1311 case OP_PACKED_SWITCH:
1312 genPackedSwitch(cUnit, mir, rlSrc[0]);
1313 break;
1314
1315 case OP_SPARSE_SWITCH:
1316 genSparseSwitch(cUnit, mir, rlSrc[0]);
1317 break;
1318
1319 case OP_CMPL_FLOAT:
1320 case OP_CMPG_FLOAT:
1321 case OP_CMPL_DOUBLE:
1322 case OP_CMPG_DOUBLE:
1323 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1324 break;
1325
1326 case OP_CMP_LONG:
1327 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1328 break;
1329
1330 case OP_IF_EQ:
1331 case OP_IF_NE:
1332 case OP_IF_LT:
1333 case OP_IF_GE:
1334 case OP_IF_GT:
1335 case OP_IF_LE: {
1336 bool backwardBranch;
1337 ArmConditionCode cond;
1338 backwardBranch = (bb->taken->startOffset <= mir->offset);
1339 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001340 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001341 }
1342 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1343 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1344 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1345 switch(opcode) {
1346 case OP_IF_EQ:
1347 cond = kArmCondEq;
1348 break;
1349 case OP_IF_NE:
1350 cond = kArmCondNe;
1351 break;
1352 case OP_IF_LT:
1353 cond = kArmCondLt;
1354 break;
1355 case OP_IF_GE:
1356 cond = kArmCondGe;
1357 break;
1358 case OP_IF_GT:
1359 cond = kArmCondGt;
1360 break;
1361 case OP_IF_LE:
1362 cond = kArmCondLe;
1363 break;
1364 default:
1365 cond = (ArmConditionCode)0;
1366 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1367 }
1368 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1369 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1370 break;
1371 }
1372
1373 case OP_IF_EQZ:
1374 case OP_IF_NEZ:
1375 case OP_IF_LTZ:
1376 case OP_IF_GEZ:
1377 case OP_IF_GTZ:
1378 case OP_IF_LEZ: {
1379 bool backwardBranch;
1380 ArmConditionCode cond;
1381 backwardBranch = (bb->taken->startOffset <= mir->offset);
1382 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001383 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001384 }
1385 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1386 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1387 switch(opcode) {
1388 case OP_IF_EQZ:
1389 cond = kArmCondEq;
1390 break;
1391 case OP_IF_NEZ:
1392 cond = kArmCondNe;
1393 break;
1394 case OP_IF_LTZ:
1395 cond = kArmCondLt;
1396 break;
1397 case OP_IF_GEZ:
1398 cond = kArmCondGe;
1399 break;
1400 case OP_IF_GTZ:
1401 cond = kArmCondGt;
1402 break;
1403 case OP_IF_LEZ:
1404 cond = kArmCondLe;
1405 break;
1406 default:
1407 cond = (ArmConditionCode)0;
1408 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1409 }
1410 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1411 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1412 break;
1413 }
1414
1415 case OP_AGET_WIDE:
1416 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1417 break;
1418 case OP_AGET:
1419 case OP_AGET_OBJECT:
1420 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1421 break;
1422 case OP_AGET_BOOLEAN:
1423 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1424 rlDest, 0);
1425 break;
1426 case OP_AGET_BYTE:
1427 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1428 break;
1429 case OP_AGET_CHAR:
1430 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1431 rlDest, 1);
1432 break;
1433 case OP_AGET_SHORT:
1434 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1435 break;
1436 case OP_APUT_WIDE:
1437 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1438 break;
1439 case OP_APUT:
1440 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1441 break;
1442 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001443 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001444 break;
1445 case OP_APUT_SHORT:
1446 case OP_APUT_CHAR:
1447 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1448 rlSrc[0], 1);
1449 break;
1450 case OP_APUT_BYTE:
1451 case OP_APUT_BOOLEAN:
1452 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1453 rlSrc[0], 0);
1454 break;
1455
1456 case OP_IGET_WIDE:
1457 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001458 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001459 break;
1460
1461 case OP_IGET:
1462 case OP_IGET_VOLATILE:
1463 case OP_IGET_OBJECT:
1464 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001465 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001466 break;
1467
1468 case OP_IGET_BOOLEAN:
1469 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001470 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001471 break;
1472
1473 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001474 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001475 break;
1476
1477 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001478 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001479 break;
1480
1481 case OP_IPUT_WIDE:
1482 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001483 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001484 break;
1485
1486 case OP_IPUT_OBJECT:
1487 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001488 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001489 break;
1490
1491 case OP_IPUT:
1492 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001493 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001494 break;
1495
1496 case OP_IPUT_BOOLEAN:
1497 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001498 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001499 break;
1500
1501 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001502 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001503 break;
1504
1505 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001506 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001507 break;
1508
1509 case OP_SGET:
1510 case OP_SGET_OBJECT:
1511 case OP_SGET_BOOLEAN:
1512 case OP_SGET_BYTE:
1513 case OP_SGET_CHAR:
1514 case OP_SGET_SHORT:
1515 genSget(cUnit, mir, rlResult, rlDest);
1516 break;
1517
1518 case OP_SGET_WIDE:
1519 genSgetWide(cUnit, mir, rlResult, rlDest);
1520 break;
1521
1522 case OP_SPUT:
1523 case OP_SPUT_OBJECT:
1524 case OP_SPUT_BOOLEAN:
1525 case OP_SPUT_BYTE:
1526 case OP_SPUT_CHAR:
1527 case OP_SPUT_SHORT:
1528 genSput(cUnit, mir, rlSrc[0]);
1529 break;
1530
1531 case OP_SPUT_WIDE:
1532 genSputWide(cUnit, mir, rlSrc[0]);
1533 break;
1534
1535 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001536 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1537 true /*range*/);
1538 break;
buzbee67bf8852011-08-17 17:51:35 -07001539 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001540 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1541 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001542 break;
1543
1544 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001545 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1546 false /*range*/);
1547 break;
buzbee67bf8852011-08-17 17:51:35 -07001548 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001549 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1550 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001551 break;
1552
1553 case OP_INVOKE_VIRTUAL:
1554 case OP_INVOKE_VIRTUAL_RANGE:
1555 genInvokeVirtual(cUnit, mir);
1556 break;
1557
1558 case OP_INVOKE_SUPER:
1559 case OP_INVOKE_SUPER_RANGE:
1560 genInvokeSuper(cUnit, mir);
1561 break;
1562
1563 case OP_INVOKE_INTERFACE:
1564 case OP_INVOKE_INTERFACE_RANGE:
1565 genInvokeInterface(cUnit, mir);
1566 break;
1567
1568 case OP_NEG_INT:
1569 case OP_NOT_INT:
1570 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1571 break;
1572
1573 case OP_NEG_LONG:
1574 case OP_NOT_LONG:
1575 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1576 break;
1577
1578 case OP_NEG_FLOAT:
1579 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1580 break;
1581
1582 case OP_NEG_DOUBLE:
1583 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1584 break;
1585
1586 case OP_INT_TO_LONG:
1587 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1588 if (rlSrc[0].location == kLocPhysReg) {
1589 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1590 } else {
1591 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1592 }
1593 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1594 rlResult.lowReg, 31);
1595 storeValueWide(cUnit, rlDest, rlResult);
1596 break;
1597
1598 case OP_LONG_TO_INT:
1599 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1600 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1601 storeValue(cUnit, rlDest, rlSrc[0]);
1602 break;
1603
1604 case OP_INT_TO_BYTE:
1605 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1606 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1607 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1608 storeValue(cUnit, rlDest, rlResult);
1609 break;
1610
1611 case OP_INT_TO_SHORT:
1612 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1613 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1614 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1615 storeValue(cUnit, rlDest, rlResult);
1616 break;
1617
1618 case OP_INT_TO_CHAR:
1619 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1620 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1621 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1622 storeValue(cUnit, rlDest, rlResult);
1623 break;
1624
1625 case OP_INT_TO_FLOAT:
1626 case OP_INT_TO_DOUBLE:
1627 case OP_LONG_TO_FLOAT:
1628 case OP_LONG_TO_DOUBLE:
1629 case OP_FLOAT_TO_INT:
1630 case OP_FLOAT_TO_LONG:
1631 case OP_FLOAT_TO_DOUBLE:
1632 case OP_DOUBLE_TO_INT:
1633 case OP_DOUBLE_TO_LONG:
1634 case OP_DOUBLE_TO_FLOAT:
1635 genConversion(cUnit, mir);
1636 break;
1637
1638 case OP_ADD_INT:
1639 case OP_SUB_INT:
1640 case OP_MUL_INT:
1641 case OP_DIV_INT:
1642 case OP_REM_INT:
1643 case OP_AND_INT:
1644 case OP_OR_INT:
1645 case OP_XOR_INT:
1646 case OP_SHL_INT:
1647 case OP_SHR_INT:
1648 case OP_USHR_INT:
1649 case OP_ADD_INT_2ADDR:
1650 case OP_SUB_INT_2ADDR:
1651 case OP_MUL_INT_2ADDR:
1652 case OP_DIV_INT_2ADDR:
1653 case OP_REM_INT_2ADDR:
1654 case OP_AND_INT_2ADDR:
1655 case OP_OR_INT_2ADDR:
1656 case OP_XOR_INT_2ADDR:
1657 case OP_SHL_INT_2ADDR:
1658 case OP_SHR_INT_2ADDR:
1659 case OP_USHR_INT_2ADDR:
1660 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1661 break;
1662
1663 case OP_ADD_LONG:
1664 case OP_SUB_LONG:
1665 case OP_MUL_LONG:
1666 case OP_DIV_LONG:
1667 case OP_REM_LONG:
1668 case OP_AND_LONG:
1669 case OP_OR_LONG:
1670 case OP_XOR_LONG:
1671 case OP_ADD_LONG_2ADDR:
1672 case OP_SUB_LONG_2ADDR:
1673 case OP_MUL_LONG_2ADDR:
1674 case OP_DIV_LONG_2ADDR:
1675 case OP_REM_LONG_2ADDR:
1676 case OP_AND_LONG_2ADDR:
1677 case OP_OR_LONG_2ADDR:
1678 case OP_XOR_LONG_2ADDR:
1679 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1680 break;
1681
buzbee67bf8852011-08-17 17:51:35 -07001682 case OP_SHL_LONG:
1683 case OP_SHR_LONG:
1684 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001685 case OP_SHL_LONG_2ADDR:
1686 case OP_SHR_LONG_2ADDR:
1687 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001688 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1689 break;
1690
1691 case OP_ADD_FLOAT:
1692 case OP_SUB_FLOAT:
1693 case OP_MUL_FLOAT:
1694 case OP_DIV_FLOAT:
1695 case OP_REM_FLOAT:
1696 case OP_ADD_FLOAT_2ADDR:
1697 case OP_SUB_FLOAT_2ADDR:
1698 case OP_MUL_FLOAT_2ADDR:
1699 case OP_DIV_FLOAT_2ADDR:
1700 case OP_REM_FLOAT_2ADDR:
1701 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1702 break;
1703
1704 case OP_ADD_DOUBLE:
1705 case OP_SUB_DOUBLE:
1706 case OP_MUL_DOUBLE:
1707 case OP_DIV_DOUBLE:
1708 case OP_REM_DOUBLE:
1709 case OP_ADD_DOUBLE_2ADDR:
1710 case OP_SUB_DOUBLE_2ADDR:
1711 case OP_MUL_DOUBLE_2ADDR:
1712 case OP_DIV_DOUBLE_2ADDR:
1713 case OP_REM_DOUBLE_2ADDR:
1714 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1715 break;
1716
1717 case OP_RSUB_INT:
1718 case OP_ADD_INT_LIT16:
1719 case OP_MUL_INT_LIT16:
1720 case OP_DIV_INT_LIT16:
1721 case OP_REM_INT_LIT16:
1722 case OP_AND_INT_LIT16:
1723 case OP_OR_INT_LIT16:
1724 case OP_XOR_INT_LIT16:
1725 case OP_ADD_INT_LIT8:
1726 case OP_RSUB_INT_LIT8:
1727 case OP_MUL_INT_LIT8:
1728 case OP_DIV_INT_LIT8:
1729 case OP_REM_INT_LIT8:
1730 case OP_AND_INT_LIT8:
1731 case OP_OR_INT_LIT8:
1732 case OP_XOR_INT_LIT8:
1733 case OP_SHL_INT_LIT8:
1734 case OP_SHR_INT_LIT8:
1735 case OP_USHR_INT_LIT8:
1736 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1737 break;
1738
1739 default:
1740 res = true;
1741 }
1742 return res;
1743}
1744
buzbeeed3e9302011-09-23 17:34:19 -07001745STATIC const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001746 "kMirOpPhi",
1747 "kMirOpNullNRangeUpCheck",
1748 "kMirOpNullNRangeDownCheck",
1749 "kMirOpLowerBound",
1750 "kMirOpPunt",
1751 "kMirOpCheckInlinePrediction",
1752};
1753
1754/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001755STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001756{
1757 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1758 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1759 strcpy(msg, extendedMIROpNames[opOffset]);
1760 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1761
1762 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1763 case kMirOpPhi: {
1764 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1765 op->flags.isNop = true;
1766 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1767 break;
1768 }
1769 default:
1770 break;
1771 }
1772}
1773
1774/* If there are any ins passed in registers that have not been promoted
1775 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001776 * Note: at this pointCopy any ins that are passed in register to their
1777 * home location */
buzbeeed3e9302011-09-23 17:34:19 -07001778STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001779{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001780 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001781 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001782 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1783 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001784 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001785 int startLoc = cUnit->method->NumRegisters() -
1786 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001787 for (int i = 0; i < inRegs; i++) {
1788 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001789 //TUNING: be smarter about flushing ins to frame
1790 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001791 if (loc.location == kLocPhysReg) {
1792 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001793 }
1794 }
1795
1796 // Handle special case of wide argument half in regs, half in frame
1797 if (inRegs == 3) {
1798 RegLocation loc = cUnit->regLocation[startLoc + 2];
1799 if (loc.wide && loc.location == kLocPhysReg) {
1800 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001801 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001802 inRegs++;
1803 }
1804 }
1805
1806 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001807 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001808 RegLocation loc = cUnit->regLocation[startLoc + i];
1809 if (loc.fpLocation == kLocPhysReg) {
1810 loc.location = kLocPhysReg;
1811 loc.fp = true;
1812 loc.lowReg = loc.fpLowReg;
1813 loc.highReg = loc.fpHighReg;
1814 }
1815 if (loc.location == kLocPhysReg) {
1816 if (loc.wide) {
buzbeeb29e4d12011-09-26 15:05:48 -07001817 if (loc.fp && (loc.lowReg & 1) != 0) {
1818 // Misaligned - need to load as a pair of singles
1819 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
1820 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
1821 } else {
1822 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1823 loc.lowReg, loc.highReg, INVALID_SREG);
1824 }
buzbee67bf8852011-08-17 17:51:35 -07001825 i++;
1826 } else {
buzbee561227c2011-09-02 15:28:19 -07001827 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001828 }
1829 }
1830 i++;
1831 }
1832}
1833
1834/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001835STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001836{
1837 MIR* mir;
1838 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1839 int blockId = bb->id;
1840
1841 cUnit->curBlock = bb;
1842 labelList[blockId].operands[0] = bb->startOffset;
1843
1844 /* Insert the block label */
1845 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1846 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1847
buzbee6181f792011-09-29 11:14:04 -07001848 /* Reset local optimization data on block boundaries */
1849 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001850 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001851 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001852
1853 ArmLIR* headLIR = NULL;
1854
1855 if (bb->blockType == kEntryBlock) {
1856 /*
1857 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1858 * mechanism know so it doesn't try to use any of them when
1859 * expanding the frame or flushing. This leaves the utility
1860 * code with a single temp: r12. This should be enough.
1861 */
1862 oatLockTemp(cUnit, r0);
1863 oatLockTemp(cUnit, r1);
1864 oatLockTemp(cUnit, r2);
1865 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001866
1867 /*
1868 * We can safely skip the stack overflow check if we're
1869 * a leaf *and* our frame size < fudge factor.
1870 */
1871 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1872 ((size_t)cUnit->frameSize <
1873 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001874 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001875 if (!skipOverflowCheck) {
1876 /* Load stack limit */
1877 loadWordDisp(cUnit, rSELF,
1878 art::Thread::StackEndOffset().Int32Value(), r12);
1879 }
buzbee67bf8852011-08-17 17:51:35 -07001880 /* Spill core callee saves */
1881 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1882 /* Need to spill any FP regs? */
1883 if (cUnit->numFPSpills) {
1884 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1885 }
buzbeecefd1872011-09-09 09:59:52 -07001886 if (!skipOverflowCheck) {
1887 opRegRegImm(cUnit, kOpSub, rLR, rSP,
1888 cUnit->frameSize - (cUnit->numSpills * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001889 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1890 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001891 genRegCopy(cUnit, rSP, rLR); // Establish stack
1892 } else {
1893 opRegImm(cUnit, kOpSub, rSP,
1894 cUnit->frameSize - (cUnit->numSpills * 4));
1895 }
buzbee67bf8852011-08-17 17:51:35 -07001896 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1897 flushIns(cUnit);
1898 oatFreeTemp(cUnit, r0);
1899 oatFreeTemp(cUnit, r1);
1900 oatFreeTemp(cUnit, r2);
1901 oatFreeTemp(cUnit, r3);
1902 } else if (bb->blockType == kExitBlock) {
1903 newLIR0(cUnit, kArmPseudoMethodExit);
1904 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1905 /* Need to restore any FP callee saves? */
1906 if (cUnit->numFPSpills) {
1907 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1908 }
1909 if (cUnit->coreSpillMask & (1 << rLR)) {
1910 /* Unspill rLR to rPC */
1911 cUnit->coreSpillMask &= ~(1 << rLR);
1912 cUnit->coreSpillMask |= (1 << rPC);
1913 }
1914 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1915 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1916 /* We didn't pop to rPC, so must do a bv rLR */
1917 newLIR1(cUnit, kThumbBx, rLR);
1918 }
1919 }
1920
1921 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1922
1923 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07001924 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1925 oatClobberAllRegs(cUnit);
1926 }
buzbee67bf8852011-08-17 17:51:35 -07001927
1928 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1929 oatResetDefTracking(cUnit);
1930 }
1931
1932 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1933 handleExtendedMethodMIR(cUnit, mir);
1934 continue;
1935 }
1936
1937 cUnit->currentDalvikOffset = mir->offset;
1938
1939 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1940 InstructionFormat dalvikFormat =
1941 dexGetFormatFromOpcode(dalvikOpcode);
1942
1943 ArmLIR* boundaryLIR;
1944
1945 /* Mark the beginning of a Dalvik instruction for line tracking */
1946 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1947 (int) oatGetDalvikDisassembly(
1948 &mir->dalvikInsn, ""));
1949 /* Remember the first LIR for this block */
1950 if (headLIR == NULL) {
1951 headLIR = boundaryLIR;
1952 /* Set the first boundaryLIR as a scheduling barrier */
1953 headLIR->defMask = ENCODE_ALL;
1954 }
1955
1956 /* Don't generate the SSA annotation unless verbose mode is on */
1957 if (cUnit->printMe && mir->ssaRep) {
1958 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1959 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1960 }
1961
1962 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1963
1964 if (notHandled) {
1965 char buf[100];
1966 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1967 mir->offset,
1968 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1969 dalvikFormat);
1970 LOG(FATAL) << buf;
1971 }
1972 }
1973
1974 if (headLIR) {
1975 /*
1976 * Eliminate redundant loads/stores and delay stores into later
1977 * slots
1978 */
1979 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1980 cUnit->lastLIRInsn);
1981
1982 /*
1983 * Generate an unconditional branch to the fallthrough block.
1984 */
1985 if (bb->fallThrough) {
1986 genUnconditionalBranch(cUnit,
1987 &labelList[bb->fallThrough->id]);
1988 }
1989 }
1990 return false;
1991}
1992
1993/*
1994 * Nop any unconditional branches that go to the next instruction.
1995 * Note: new redundant branches may be inserted later, and we'll
1996 * use a check in final instruction assembly to nop those out.
1997 */
1998void removeRedundantBranches(CompilationUnit* cUnit)
1999{
2000 ArmLIR* thisLIR;
2001
2002 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2003 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2004 thisLIR = NEXT_LIR(thisLIR)) {
2005
2006 /* Branch to the next instruction */
2007 if ((thisLIR->opcode == kThumbBUncond) ||
2008 (thisLIR->opcode == kThumb2BUncond)) {
2009 ArmLIR* nextLIR = thisLIR;
2010
2011 while (true) {
2012 nextLIR = NEXT_LIR(nextLIR);
2013
2014 /*
2015 * Is the branch target the next instruction?
2016 */
2017 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2018 thisLIR->flags.isNop = true;
2019 break;
2020 }
2021
2022 /*
2023 * Found real useful stuff between the branch and the target.
2024 * Need to explicitly check the lastLIRInsn here because it
2025 * might be the last real instruction.
2026 */
2027 if (!isPseudoOpcode(nextLIR->opcode) ||
2028 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2029 break;
2030 }
2031 }
2032 }
2033}
2034
buzbeeed3e9302011-09-23 17:34:19 -07002035STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002036{
2037 ArmLIR** suspendLabel =
2038 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2039 int numElems = cUnit->suspendLaunchpads.numUsed;
2040
2041 for (int i = 0; i < numElems; i++) {
2042 /* TUNING: move suspend count load into helper */
2043 ArmLIR* lab = suspendLabel[i];
2044 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2045 cUnit->currentDalvikOffset = lab->operands[1];
2046 oatAppendLIR(cUnit, (LIR *)lab);
2047 loadWordDisp(cUnit, rSELF,
2048 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2049 loadWordDisp(cUnit, rSELF,
2050 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2051 opReg(cUnit, kOpBlx, rLR);
2052 genUnconditionalBranch(cUnit, resumeLab);
2053 }
2054}
2055
buzbeeed3e9302011-09-23 17:34:19 -07002056STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002057{
2058 ArmLIR** throwLabel =
2059 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2060 int numElems = cUnit->throwLaunchpads.numUsed;
2061 int i;
2062
2063 for (i = 0; i < numElems; i++) {
2064 ArmLIR* lab = throwLabel[i];
2065 cUnit->currentDalvikOffset = lab->operands[1];
2066 oatAppendLIR(cUnit, (LIR *)lab);
2067 int funcOffset = 0;
2068 int v1 = lab->operands[2];
2069 int v2 = lab->operands[3];
2070 switch(lab->operands[0]) {
2071 case kArmThrowNullPointer:
2072 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2073 break;
2074 case kArmThrowArrayBounds:
2075 if (v2 != r0) {
2076 genRegCopy(cUnit, r0, v1);
2077 genRegCopy(cUnit, r1, v2);
2078 } else {
2079 if (v1 == r1) {
2080 genRegCopy(cUnit, r12, v1);
2081 genRegCopy(cUnit, r1, v2);
2082 genRegCopy(cUnit, r0, r12);
2083 } else {
2084 genRegCopy(cUnit, r1, v2);
2085 genRegCopy(cUnit, r0, v1);
2086 }
2087 }
2088 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2089 break;
2090 case kArmThrowDivZero:
2091 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2092 break;
2093 case kArmThrowVerificationError:
2094 loadConstant(cUnit, r0, v1);
2095 loadConstant(cUnit, r1, v2);
2096 funcOffset =
2097 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2098 break;
2099 case kArmThrowNegArraySize:
2100 genRegCopy(cUnit, r0, v1);
2101 funcOffset =
2102 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2103 break;
2104 case kArmThrowInternalError:
2105 genRegCopy(cUnit, r0, v1);
2106 funcOffset =
2107 OFFSETOF_MEMBER(Thread, pThrowInternalErrorFromCode);
2108 break;
2109 case kArmThrowRuntimeException:
2110 genRegCopy(cUnit, r0, v1);
2111 funcOffset =
2112 OFFSETOF_MEMBER(Thread, pThrowRuntimeExceptionFromCode);
2113 break;
2114 case kArmThrowNoSuchMethod:
2115 genRegCopy(cUnit, r0, v1);
2116 funcOffset =
2117 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2118 break;
buzbeeec5adf32011-09-11 15:25:43 -07002119 case kArmThrowStackOverflow:
2120 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002121 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002122 // Restore stack alignment
2123 opRegImm(cUnit, kOpAdd, rSP, cUnit->numSpills * 4);
2124 break;
buzbee5ade1d22011-09-09 14:44:52 -07002125 default:
2126 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2127 }
2128 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002129 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002130 }
2131}
2132
buzbee67bf8852011-08-17 17:51:35 -07002133void oatMethodMIR2LIR(CompilationUnit* cUnit)
2134{
2135 /* Used to hold the labels of each block */
2136 cUnit->blockLabelList =
2137 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2138
2139 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2140 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002141 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002142
2143 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002144
2145 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002146}
2147
2148/* Common initialization routine for an architecture family */
2149bool oatArchInit()
2150{
2151 int i;
2152
2153 for (i = 0; i < kArmLast; i++) {
2154 if (EncodingMap[i].opcode != i) {
2155 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2156 " is wrong: expecting " << i << ", seeing " <<
2157 (int)EncodingMap[i].opcode;
2158 }
2159 }
2160
2161 return oatArchVariantInit();
2162}
2163
2164/* Needed by the Assembler */
2165void oatSetupResourceMasks(ArmLIR* lir)
2166{
2167 setupResourceMasks(lir);
2168}
2169
2170/* Needed by the ld/st optmizatons */
2171ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2172{
2173 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2174}
2175
2176/* Needed by the register allocator */
2177ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2178{
2179 return genRegCopy(cUnit, rDest, rSrc);
2180}
2181
2182/* Needed by the register allocator */
2183void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2184 int srcLo, int srcHi)
2185{
2186 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2187}
2188
2189void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2190 int displacement, int rSrc, OpSize size)
2191{
2192 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2193}
2194
2195void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2196 int displacement, int rSrcLo, int rSrcHi)
2197{
2198 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2199}