blob: aeb0134337f30614df888d23385763ed892cb512 [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};
buzbeeed3e9302011-09-23 17:34:19 -070023STATIC const RegLocation retLoc = LOC_DALVIK_RETURN_VAL;
24STATIC const RegLocation retLocWide = LOC_DALVIK_RETURN_VAL_WIDE;
buzbee67bf8852011-08-17 17:51:35 -070025
buzbeedfd3d702011-08-28 12:56:51 -070026/*
27 * Let helper function take care of everything. Will call
28 * Array::AllocFromCode(type_idx, method, count);
29 * Note: AllocFromCode will handle checks for errNegativeArraySize.
30 */
buzbeeed3e9302011-09-23 17:34:19 -070031STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -070032 RegLocation rlSrc)
33{
buzbeedfd3d702011-08-28 12:56:51 -070034 oatFlushAllRegs(cUnit); /* Everything to home location */
35 loadWordDisp(cUnit, rSELF,
Ian Rogersb886da82011-09-23 16:27:54 -070036 OFFSETOF_MEMBER(Thread, pArrayAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070037 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
38 loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
39 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070040 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070041 oatClobberCallRegs(cUnit);
42 RegLocation rlResult = oatGetReturn(cUnit);
43 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070044}
45
46/*
47 * Similar to genNewArray, but with post-allocation initialization.
48 * Verifier guarantees we're dealing with an array class. Current
49 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
50 * Current code also throws internal unimp if not 'L', '[' or 'I'.
51 */
buzbeeed3e9302011-09-23 17:34:19 -070052STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070053{
54 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070055 int elems = dInsn->vA;
56 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070057 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070058 loadWordDisp(cUnit, rSELF,
Ian Rogersb886da82011-09-23 16:27:54 -070059 OFFSETOF_MEMBER(Thread, pCheckAndArrayAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070060 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
61 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
62 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070063 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070064 /*
buzbeedfd3d702011-08-28 12:56:51 -070065 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
66 * return region. Because AllocFromCode placed the new array
67 * in r0, we'll just lock it into place. When debugger support is
68 * added, it may be necessary to additionally copy all return
69 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070070 */
buzbee67bf8852011-08-17 17:51:35 -070071 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070072
buzbee67bf8852011-08-17 17:51:35 -070073 // Having a range of 0 is legal
74 if (isRange && (dInsn->vA > 0)) {
75 /*
76 * Bit of ugliness here. We're going generate a mem copy loop
77 * on the register range, but it is possible that some regs
78 * in the range have been promoted. This is unlikely, but
79 * before generating the copy, we'll just force a flush
80 * of any regs in the source range that have been promoted to
81 * home location.
82 */
83 for (unsigned int i = 0; i < dInsn->vA; i++) {
84 RegLocation loc = oatUpdateLoc(cUnit,
85 oatGetSrc(cUnit, mir, i));
86 if (loc.location == kLocPhysReg) {
87 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
88 }
89 }
90 /*
91 * TUNING note: generated code here could be much improved, but
92 * this is an uncommon operation and isn't especially performance
93 * critical.
94 */
95 int rSrc = oatAllocTemp(cUnit);
96 int rDst = oatAllocTemp(cUnit);
97 int rIdx = oatAllocTemp(cUnit);
98 int rVal = rLR; // Using a lot of temps, rLR is known free here
99 // Set up source pointer
100 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
101 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
102 // Set up the target pointer
103 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700104 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700105 // Set up the loop counter (known to be > 0)
106 loadConstant(cUnit, rIdx, dInsn->vA);
107 // Generate the copy loop. Going backwards for convenience
108 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
109 target->defMask = ENCODE_ALL;
110 // Copy next element
111 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
112 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
113 // Use setflags encoding here
114 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
115 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
116 branch->generic.target = (LIR*)target;
117 } else if (!isRange) {
118 // TUNING: interleave
119 for (unsigned int i = 0; i < dInsn->vA; i++) {
120 RegLocation rlArg = loadValue(cUnit,
121 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700122 storeBaseDisp(cUnit, r0,
123 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700124 i * 4, rlArg.lowReg, kWord);
125 // If the loadValue caused a temp to be allocated, free it
126 if (oatIsTemp(cUnit, rlArg.lowReg)) {
127 oatFreeTemp(cUnit, rlArg.lowReg);
128 }
129 }
130 }
131}
132
Brian Carlstrom845490b2011-09-19 15:56:53 -0700133Field* FindFieldWithResolvedStaticStorage(const Method* method,
134 const uint32_t fieldIdx,
135 uint32_t& resolvedTypeIdx) {
136 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
137 Field* field = class_linker->ResolveField(fieldIdx, method, true);
138 if (field == NULL) {
139 return NULL;
140 }
141 const art::DexFile& dex_file = class_linker->
142 FindDexFile(method->GetDeclaringClass()->GetDexCache());
143 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
144 int type_idx = field_id.class_idx_;
145 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
146 // Check if storage class is the same as class referred to by type idx.
147 // They may not be if the FieldId refers a subclass, but storage is in super
148 if (field->GetDeclaringClass() == klass) {
149 resolvedTypeIdx = type_idx;
150 return field;
151 }
152 // See if we can find a dex reference for the storage class.
153 // we may not if the dex file never references the super class,
154 // but usually it will.
155 std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
156 for (size_t type_idx = 0; type_idx < dex_file.NumTypeIds(); type_idx++) {
157 const art::DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
158 if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
159 resolvedTypeIdx = type_idx;
160 return field;
161 }
162 }
163 return NULL; // resort to slow path
164}
165
buzbeeed3e9302011-09-23 17:34:19 -0700166STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700167{
buzbeee1931742011-08-28 21:15:53 -0700168 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
169 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700170 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700171 uint32_t typeIdx;
172 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
173 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700174 // Slow path
buzbee34cd9e52011-09-08 14:31:52 -0700175 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
176 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700177 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
178 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700179 oatFlushAllRegs(cUnit);
180 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
181 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
182 loadCurrMethodDirect(cUnit, r1);
183 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700184 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700185 oatClobberCallRegs(cUnit);
186 } else {
buzbee1da522d2011-09-04 11:22:20 -0700187 // fast path
188 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700189 // Using fixed register to sync with slow path
190 int rMethod = r1;
191 oatLockTemp(cUnit, rMethod);
192 loadCurrMethodDirect(cUnit, rMethod);
193 int rBase = r0;
194 oatLockTemp(cUnit, rBase);
195 loadWordDisp(cUnit, rMethod,
196 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
197 rBase);
198 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
199 sizeof(int32_t*)* typeIdx, rBase);
200 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700201 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700202 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
203 loadWordDisp(cUnit, rSELF,
204 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
205 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700206 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700207 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
208 skipTarget->defMask = ENCODE_ALL;
209 branchOver->generic.target = (LIR*)skipTarget;
210 rlSrc = oatGetSrc(cUnit, mir, 0);
211 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
212 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700213#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700214 if (field->IsVolatile()) {
215 oatGenMemBarrier(cUnit, kSY);
216 }
buzbee67bf8852011-08-17 17:51:35 -0700217#endif
buzbee1da522d2011-09-04 11:22:20 -0700218 if (isObject) {
219 markGCCard(cUnit, rlSrc.lowReg, rBase);
220 }
221 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700222 }
buzbee67bf8852011-08-17 17:51:35 -0700223}
224
buzbeeed3e9302011-09-23 17:34:19 -0700225STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700226{
buzbee1da522d2011-09-04 11:22:20 -0700227 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700228 uint32_t typeIdx;
229 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700230 if (SLOW_FIELD_PATH || field == NULL) {
231 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
232 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700233 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700234 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700235 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
236 loadCurrMethodDirect(cUnit, r1);
237 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700238 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700239 oatClobberCallRegs(cUnit);
240 } else {
buzbee1da522d2011-09-04 11:22:20 -0700241 // fast path
242 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700243 // Using fixed register to sync with slow path
244 int rMethod = r1;
245 oatLockTemp(cUnit, rMethod);
246 loadCurrMethodDirect(cUnit, r1);
247 int rBase = r0;
248 oatLockTemp(cUnit, rBase);
249 loadWordDisp(cUnit, rMethod,
250 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
251 rBase);
252 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
253 sizeof(int32_t*)* typeIdx, rBase);
254 // TUNING: fast path should fall through
255 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
256 loadWordDisp(cUnit, rSELF,
257 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
258 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700259 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700260 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
261 skipTarget->defMask = ENCODE_ALL;
262 branchOver->generic.target = (LIR*)skipTarget;
263 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
264 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
265 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
266 rlSrc.highReg);
267#if ANDROID_SMP != 0
268 if (field->IsVolatile()) {
269 oatGenMemBarrier(cUnit, kSY);
270 }
buzbeec143c552011-08-20 17:38:58 -0700271#endif
buzbee1da522d2011-09-04 11:22:20 -0700272 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700273 }
buzbee67bf8852011-08-17 17:51:35 -0700274}
275
276
buzbeeed3e9302011-09-23 17:34:19 -0700277STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700278 RegLocation rlResult, RegLocation rlDest)
279{
buzbee1da522d2011-09-04 11:22:20 -0700280 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700281 uint32_t typeIdx;
282 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700283 if (SLOW_FIELD_PATH || field == NULL) {
284 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
285 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700286 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700287 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700288 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
289 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700290 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700291 RegLocation rlResult = oatGetReturnWide(cUnit);
292 storeValueWide(cUnit, rlDest, rlResult);
293 } else {
buzbee1da522d2011-09-04 11:22:20 -0700294 // Fast path
295 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700296 // Using fixed register to sync with slow path
297 int rMethod = r1;
298 oatLockTemp(cUnit, rMethod);
299 loadCurrMethodDirect(cUnit, rMethod);
300 int rBase = r0;
301 oatLockTemp(cUnit, rBase);
302 loadWordDisp(cUnit, rMethod,
303 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
304 rBase);
305 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
306 sizeof(int32_t*)* typeIdx, rBase);
307 // TUNING: fast path should fall through
308 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
309 loadWordDisp(cUnit, rSELF,
310 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
311 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700312 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700313 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
314 skipTarget->defMask = ENCODE_ALL;
315 branchOver->generic.target = (LIR*)skipTarget;
316 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
317 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
318#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700319 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700320 oatGenMemBarrier(cUnit, kSY);
321 }
buzbeec143c552011-08-20 17:38:58 -0700322#endif
buzbee1da522d2011-09-04 11:22:20 -0700323 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
324 rlResult.highReg, INVALID_SREG);
325 oatFreeTemp(cUnit, rBase);
326 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700327 }
buzbee67bf8852011-08-17 17:51:35 -0700328}
329
buzbeeed3e9302011-09-23 17:34:19 -0700330STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700331 RegLocation rlResult, RegLocation rlDest)
332{
buzbee1da522d2011-09-04 11:22:20 -0700333 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700334 uint32_t typeIdx;
335 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700336 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
337 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee34cd9e52011-09-08 14:31:52 -0700338 if (SLOW_FIELD_PATH || field == NULL) {
339 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
340 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700341 // Slow path
342 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
343 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700344 oatFlushAllRegs(cUnit);
345 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
346 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
347 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700348 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700349 RegLocation rlResult = oatGetReturn(cUnit);
350 storeValue(cUnit, rlDest, rlResult);
351 } else {
buzbee1da522d2011-09-04 11:22:20 -0700352 // Fast path
353 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700354 // Using fixed register to sync with slow path
355 int rMethod = r1;
356 oatLockTemp(cUnit, rMethod);
357 loadCurrMethodDirect(cUnit, rMethod);
358 int rBase = r0;
359 oatLockTemp(cUnit, rBase);
360 loadWordDisp(cUnit, rMethod,
361 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
362 rBase);
363 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
364 sizeof(int32_t*)* typeIdx, rBase);
365 // TUNING: fast path should fall through
366 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
367 loadWordDisp(cUnit, rSELF,
368 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
369 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700370 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700371 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
372 skipTarget->defMask = ENCODE_ALL;
373 branchOver->generic.target = (LIR*)skipTarget;
374 rlDest = oatGetDest(cUnit, mir, 0);
375 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700376#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700377 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700378 oatGenMemBarrier(cUnit, kSY);
379 }
buzbee67bf8852011-08-17 17:51:35 -0700380#endif
buzbee1da522d2011-09-04 11:22:20 -0700381 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
382 oatFreeTemp(cUnit, rBase);
383 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700384 }
buzbee67bf8852011-08-17 17:51:35 -0700385}
386
buzbee561227c2011-09-02 15:28:19 -0700387typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
388 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700389
390/*
391 * Bit of a hack here - in leiu of a real scheduling pass,
392 * emit the next instruction in static & direct invoke sequences.
393 */
buzbeeed3e9302011-09-23 17:34:19 -0700394STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700395 DecodedInstruction* dInsn, int state,
396 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700397{
buzbee561227c2011-09-02 15:28:19 -0700398 DCHECK(rollback == NULL);
399 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700400 switch(state) {
401 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700402 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700403 break;
buzbee561227c2011-09-02 15:28:19 -0700404 case 1: // Get method->code_and_direct_methods_
405 loadWordDisp(cUnit, r0,
406 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
407 r0);
buzbee67bf8852011-08-17 17:51:35 -0700408 break;
buzbee561227c2011-09-02 15:28:19 -0700409 case 2: // Grab target method* and target code_
410 loadWordDisp(cUnit, r0,
411 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
412 loadWordDisp(cUnit, r0,
413 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700414 break;
415 default:
416 return -1;
417 }
418 return state + 1;
419}
420
buzbee67bf8852011-08-17 17:51:35 -0700421/*
422 * Bit of a hack here - in leiu of a real scheduling pass,
423 * emit the next instruction in a virtual invoke sequence.
424 * We can use rLR as a temp prior to target address loading
425 * Note also that we'll load the first argument ("this") into
426 * r1 here rather than the standard loadArgRegs.
427 */
buzbeeed3e9302011-09-23 17:34:19 -0700428STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700429 DecodedInstruction* dInsn, int state,
430 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700431{
buzbee561227c2011-09-02 15:28:19 -0700432 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700433 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700434 /*
435 * This is the fast path in which the target virtual method is
436 * fully resolved at compile time.
437 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700438 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
439 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -0700440 CHECK(baseMethod != NULL);
441 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700442 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700443 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700444 rlArg = oatGetSrc(cUnit, mir, 0);
445 loadValueDirectFixed(cUnit, rlArg, r1);
446 break;
buzbee561227c2011-09-02 15:28:19 -0700447 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700448 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700449 // get this->klass_ [use r1, set rLR]
450 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700451 break;
buzbee561227c2011-09-02 15:28:19 -0700452 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
453 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700454 break;
buzbee561227c2011-09-02 15:28:19 -0700455 case 3: // Get target method [use rLR, set r0]
456 loadWordDisp(cUnit, rLR, (target_idx * 4) +
457 art::Array::DataOffset().Int32Value(), r0);
458 break;
459 case 4: // Get the target compiled code address [uses r0, sets rLR]
460 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700461 break;
462 default:
463 return -1;
464 }
465 return state + 1;
466}
467
buzbeeed3e9302011-09-23 17:34:19 -0700468STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700469 DecodedInstruction* dInsn, int state,
470 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700471{
buzbeeed3e9302011-09-23 17:34:19 -0700472 DCHECK(rollback == NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700473 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700474 ArmLIR* skipBranch;
475 ArmLIR* skipTarget;
476 /*
477 * This handles the case in which the base method is not fully
478 * resolved at compile time. We must generate code to test
479 * for resolution a run time, bail to the slow path if not to
480 * fill in all the tables. In the latter case, we'll restart at
481 * at the beginning of the sequence.
482 */
buzbee7b1b86d2011-08-26 18:59:10 -0700483 switch(state) {
484 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700485 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700486 break;
buzbee561227c2011-09-02 15:28:19 -0700487 case 1: // Get method->dex_cache_resolved_methods_
488 loadWordDisp(cUnit, r0,
489 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700490 break;
buzbee561227c2011-09-02 15:28:19 -0700491 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
492 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
493 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700494 break;
buzbee561227c2011-09-02 15:28:19 -0700495 case 3: // Resolved?
496 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
497 // Slowest path, bail to helper, rollback and retry
498 loadWordDisp(cUnit, rSELF,
499 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
500 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700501 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700502 genUnconditionalBranch(cUnit, rollback);
503 // Resume normal slow path
504 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
505 skipTarget->defMask = ENCODE_ALL;
506 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700507 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700508 loadBaseDisp(cUnit, mir, rLR,
509 Method::GetMethodIndexOffset().Int32Value(), r0,
510 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700511 // Load "this" [set r1]
512 rlArg = oatGetSrc(cUnit, mir, 0);
513 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700514 break;
515 case 4:
516 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700517 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700518 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700519 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700520 break;
buzbee561227c2011-09-02 15:28:19 -0700521 case 5:
522 // get this->klass_->vtable_ [usr rLR, set rLR]
523 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700524 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700525 // In load shadow fold vtable_ object header size into method_index_
526 opRegImm(cUnit, kOpAdd, r0,
527 art::Array::DataOffset().Int32Value() / 4);
528 // Get target Method*
529 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
530 break;
531 case 6: // Get the target compiled code address [uses r0, sets rLR]
532 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700533 break;
534 default:
535 return -1;
536 }
537 return state + 1;
538}
539
buzbeeed3e9302011-09-23 17:34:19 -0700540STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700541 DecodedInstruction* dInsn, int callState,
542 NextCallInsn nextCallInsn, ArmLIR* rollback,
543 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700544{
buzbeec0ecd652011-09-25 18:11:54 -0700545 int nextReg = r1;
546 int nextArg = 0;
547 if (skipThis) {
548 nextReg++;
549 nextArg++;
550 }
551 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
552 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
553 rlArg = oatUpdateRawLoc(cUnit, rlArg);
554 if (rlArg.wide && (nextReg <= r2)) {
555 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
556 nextReg++;
557 nextArg++;
558 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700559 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700560 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700561 }
buzbeec0ecd652011-09-25 18:11:54 -0700562 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700563 }
564 return callState;
565}
566
buzbee4a3164f2011-09-03 11:25:10 -0700567// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700568STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700569 DecodedInstruction* dInsn, int state,
570 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700571{
buzbee67bf8852011-08-17 17:51:35 -0700572 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700573 case 0: // Load trampoline target
574 loadWordDisp(cUnit, rSELF,
575 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
576 rLR);
577 // Load r0 with method index
578 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700579 break;
buzbee67bf8852011-08-17 17:51:35 -0700580 default:
581 return -1;
582 }
583 return state + 1;
584}
585
buzbee67bf8852011-08-17 17:51:35 -0700586/*
587 * Interleave launch code for INVOKE_SUPER. See comments
588 * for nextVCallIns.
589 */
buzbeeed3e9302011-09-23 17:34:19 -0700590STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700591 DecodedInstruction* dInsn, int state,
592 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700593{
buzbee4a3164f2011-09-03 11:25:10 -0700594 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700595 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700596 /*
597 * This is the fast path in which the target virtual method is
598 * fully resolved at compile time. Note also that this path assumes
599 * that the check to verify that the target method index falls
600 * within the size of the super's vtable has been done at compile-time.
601 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700602 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
603 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700604 CHECK(baseMethod != NULL);
605 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
606 CHECK(superClass != NULL);
607 int32_t target_idx = baseMethod->GetMethodIndex();
608 CHECK(superClass->GetVTable()->GetLength() > target_idx);
609 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
610 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700611 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700612 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700613 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700614 // Load "this" [set r1]
615 rlArg = oatGetSrc(cUnit, mir, 0);
616 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700617 // Get method->declaring_class_ [use r0, set rLR]
618 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
619 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700620 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700621 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700622 break;
623 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
624 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
625 rLR);
626 break;
627 case 2: // Get ...->super_class_->vtable [u/s rLR]
628 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
629 break;
630 case 3: // Get target method [use rLR, set r0]
631 loadWordDisp(cUnit, rLR, (target_idx * 4) +
632 art::Array::DataOffset().Int32Value(), r0);
633 break;
634 case 4: // Get the target compiled code address [uses r0, sets rLR]
635 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
636 break;
buzbee67bf8852011-08-17 17:51:35 -0700637 default:
638 return -1;
639 }
buzbee4a3164f2011-09-03 11:25:10 -0700640 return state + 1;
641}
642
643/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700644STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700645 DecodedInstruction* dInsn, int state,
646 ArmLIR* rollback)
647{
buzbeeed3e9302011-09-23 17:34:19 -0700648 DCHECK(rollback == NULL);
buzbee4a3164f2011-09-03 11:25:10 -0700649 RegLocation rlArg;
650 ArmLIR* skipBranch;
651 ArmLIR* skipTarget;
652 int tReg;
653 /*
654 * This handles the case in which the base method is not fully
655 * resolved at compile time. We must generate code to test
656 * for resolution a run time, bail to the slow path if not to
657 * fill in all the tables. In the latter case, we'll restart at
658 * at the beginning of the sequence.
659 */
660 switch(state) {
661 case 0: // Get the current Method* [sets r0]
662 loadCurrMethodDirect(cUnit, r0);
663 break;
664 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
665 loadWordDisp(cUnit, r0,
666 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
667 break;
668 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
669 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
670 art::Array::DataOffset().Int32Value(), rLR);
671 break;
672 case 3: // Resolved?
673 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
674 // Slowest path, bail to helper, rollback and retry
675 loadWordDisp(cUnit, rSELF,
676 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
677 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700678 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700679 genUnconditionalBranch(cUnit, rollback);
680 // Resume normal slow path
681 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
682 skipTarget->defMask = ENCODE_ALL;
683 skipBranch->generic.target = (LIR*)skipTarget;
684 // Get base_method->method_index [usr rLR, set rLR]
685 loadBaseDisp(cUnit, mir, rLR,
686 Method::GetMethodIndexOffset().Int32Value(), rLR,
687 kUnsignedHalf, INVALID_SREG);
688 // Load "this" [set r1]
689 rlArg = oatGetSrc(cUnit, mir, 0);
690 loadValueDirectFixed(cUnit, rlArg, r1);
691 // Load curMethod->declaring_class_ [uses r0, sets r0]
692 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
693 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700694 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700695 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700696 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700697 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
698 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700699 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700700 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700701 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700702 // Range check, throw NSM on failure
703 tReg = oatAllocTemp(cUnit);
704 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
705 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700706 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
707 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700708 oatFreeTemp(cUnit, tReg);
709 }
buzbee6a0f7f52011-09-05 16:14:20 -0700710 // Adjust vtable_ base past object header
711 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700712 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700713 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700714 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700715 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700716 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
717 break;
718 default:
719 return -1;
720 }
buzbee67bf8852011-08-17 17:51:35 -0700721 return state + 1;
722}
723
724/*
725 * Load up to 5 arguments, the first three of which will be in
726 * r1 .. r3. On entry r0 contains the current method pointer,
727 * and as part of the load sequence, it must be replaced with
728 * the target method pointer. Note, this may also be called
729 * for "range" variants if the number of arguments is 5 or fewer.
730 */
buzbeeed3e9302011-09-23 17:34:19 -0700731STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700732 DecodedInstruction* dInsn, int callState,
733 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700734 NextCallInsn nextCallInsn, ArmLIR* rollback,
735 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700736{
737 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700738
739 /* If no arguments, just return */
740 if (dInsn->vA == 0)
741 return callState;
742
buzbee561227c2011-09-02 15:28:19 -0700743 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700744
buzbeec0ecd652011-09-25 18:11:54 -0700745 DCHECK_LE(dInsn->vA, 5U);
746 if (dInsn->vA > 3) {
747 uint32_t nextUse = 3;
748 //Detect special case of wide arg spanning arg3/arg4
749 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
750 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
751 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
752 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
753 rlUse2.wide) {
754 int reg;
755 // Wide spans, we need the 2nd half of uses[2].
756 rlArg = oatUpdateLocWide(cUnit, rlUse2);
757 if (rlArg.location == kLocPhysReg) {
758 reg = rlArg.highReg;
759 } else {
760 // r2 & r3 can safely be used here
761 reg = r3;
762 loadWordDisp(cUnit, rSP, rlArg.spOffset + 4, reg);
763 callState = nextCallInsn(cUnit, mir, dInsn, callState,
764 rollback);
765 }
766 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
767 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
768 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
769 nextUse++;
770 }
771 // Loop through the rest
772 while (nextUse < dInsn->vA) {
773 int lowReg;
774 int highReg;
775 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
776 rlArg = oatUpdateRawLoc(cUnit, rlArg);
777 if (rlArg.location == kLocPhysReg) {
778 lowReg = rlArg.lowReg;
779 highReg = rlArg.highReg;
780 } else {
781 lowReg = r2;
782 highReg = r3;
783 if (rlArg.wide) {
784 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
785 } else {
786 loadValueDirectFixed(cUnit, rlArg, lowReg);
787 }
788 callState = nextCallInsn(cUnit, mir, dInsn, callState,
789 rollback);
790 }
791 int outsOffset = (nextUse + 1) * 4;
792 if (rlArg.wide) {
793 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
794 nextUse += 2;
795 } else {
796 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
797 nextUse++;
798 }
buzbee561227c2011-09-02 15:28:19 -0700799 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700800 }
buzbee67bf8852011-08-17 17:51:35 -0700801 }
802
buzbeec0ecd652011-09-25 18:11:54 -0700803 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
804 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700805
buzbee6a0f7f52011-09-05 16:14:20 -0700806 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700807 // Load direct & need a "this" null check?
808 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700809 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700810 }
811 return callState;
812}
813
814/*
815 * May have 0+ arguments (also used for jumbo). Note that
816 * source virtual registers may be in physical registers, so may
817 * need to be flushed to home location before copying. This
818 * applies to arg3 and above (see below).
819 *
820 * Two general strategies:
821 * If < 20 arguments
822 * Pass args 3-18 using vldm/vstm block copy
823 * Pass arg0, arg1 & arg2 in r1-r3
824 * If 20+ arguments
825 * Pass args arg19+ using memcpy block copy
826 * Pass arg0, arg1 & arg2 in r1-r3
827 *
828 */
buzbeeed3e9302011-09-23 17:34:19 -0700829STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700830 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700831 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700832 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700833{
834 int firstArg = dInsn->vC;
835 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700836
buzbee67bf8852011-08-17 17:51:35 -0700837 // If we can treat it as non-range (Jumbo ops will use range form)
838 if (numArgs <= 5)
839 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700840 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700841 /*
842 * Make sure range list doesn't span the break between in normal
843 * Dalvik vRegs and the ins.
844 */
buzbee1b4c8592011-08-31 10:43:51 -0700845 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700846 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700847 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
848 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700849 }
850
851 /*
852 * First load the non-register arguments. Both forms expect all
853 * of the source arguments to be in their home frame location, so
854 * scan the sReg names and flush any that have been promoted to
855 * frame backing storage.
856 */
857 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700858 for (int nextArg = 0; nextArg < numArgs;) {
859 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700860 if (loc.wide) {
861 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700862 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee1b4c8592011-08-31 10:43:51 -0700863 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
864 loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700865 }
buzbeec0ecd652011-09-25 18:11:54 -0700866 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700867 } else {
868 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700869 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee1b4c8592011-08-31 10:43:51 -0700870 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700871 }
buzbeec0ecd652011-09-25 18:11:54 -0700872 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700873 }
874 }
875
876 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
877 int outsOffset = 4 /* Method* */ + (3 * 4);
878 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700879 // Generate memcpy
880 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
881 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700882 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
883 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700884 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700885 // Restore Method*
886 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700887 } else {
888 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700889 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700890 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700891 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700892 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
893 //TUNING: loosen barrier
894 ld->defMask = ENCODE_ALL;
895 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700896 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700897 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700898 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700899 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
900 setMemRefType(st, false /* isLoad */, kDalvikReg);
901 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700902 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700903 }
904
buzbeec0ecd652011-09-25 18:11:54 -0700905 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
906 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700907
buzbee561227c2011-09-02 15:28:19 -0700908 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700909 return callState;
910}
911
buzbee2a475e72011-09-07 17:19:17 -0700912#ifdef DISPLAY_MISSING_TARGETS
913// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700914STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700915{
916 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
917 loadWordDisp(cUnit, rSELF,
918 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
919 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
920 target->defMask = -1;
921 branchOver->generic.target = (LIR*)target;
922}
923#endif
924
buzbeeed3e9302011-09-23 17:34:19 -0700925STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700926 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700927{
928 DecodedInstruction* dInsn = &mir->dalvikInsn;
929 int callState = 0;
930 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700931 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700932 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700933 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700934
buzbee109bd6a2011-09-06 13:58:41 -0700935 // Explicit register usage
936 oatLockCallTemps(cUnit);
937
buzbee561227c2011-09-02 15:28:19 -0700938 if (range) {
939 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700940 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700941 } else {
942 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700943 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700944 }
buzbee67bf8852011-08-17 17:51:35 -0700945 // Finish up any of the call sequence not interleaved in arg loading
946 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700947 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700948 }
buzbee2a475e72011-09-07 17:19:17 -0700949#ifdef DISPLAY_MISSING_TARGETS
950 genShowTarget(cUnit);
951#endif
buzbeeec5adf32011-09-11 15:25:43 -0700952 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700953}
954
buzbee4a3164f2011-09-03 11:25:10 -0700955/*
956 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
957 * which will locate the target and continue on via a tail call.
958 */
buzbeeed3e9302011-09-23 17:34:19 -0700959STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -0700960{
961 DecodedInstruction* dInsn = &mir->dalvikInsn;
962 int callState = 0;
963 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -0700964 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -0700965
966 // Explicit register usage
967 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700968 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700969 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700970 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
971 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700972 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -0700973 false);
buzbee67bf8852011-08-17 17:51:35 -0700974 else
975 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -0700976 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -0700977 // Finish up any of the call sequence not interleaved in arg loading
978 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700979 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700980 }
buzbee2a475e72011-09-07 17:19:17 -0700981#ifdef DISPLAY_MISSING_TARGETS
982 genShowTarget(cUnit);
983#endif
buzbeeec5adf32011-09-11 15:25:43 -0700984 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700985}
986
buzbeeed3e9302011-09-23 17:34:19 -0700987STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -0700988{
989 DecodedInstruction* dInsn = &mir->dalvikInsn;
990 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -0700991 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700992 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
993 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700994 NextCallInsn nextCallInsn;
995 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -0700996 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -0700997
998 // Explicit register usage
999 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001000 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -07001001 fastPath = false;
1002 } else {
1003 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
1004 if (superClass == NULL) {
1005 fastPath = false;
1006 } else {
1007 int32_t target_idx = baseMethod->GetMethodIndex();
1008 if (superClass->GetVTable()->GetLength() <= target_idx) {
1009 fastPath = false;
1010 } else {
1011 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1012 }
1013 }
1014 }
1015 if (fastPath) {
1016 nextCallInsn = nextSuperCallInsn;
1017 rollback = NULL;
1018 } else {
1019 nextCallInsn = nextSuperCallInsnSP;
1020 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1021 rollback->defMask = -1;
1022 }
buzbee67bf8852011-08-17 17:51:35 -07001023 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001024 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001025 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001026 else
buzbeec0ecd652011-09-25 18:11:54 -07001027 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001028 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001029 // Finish up any of the call sequence not interleaved in arg loading
1030 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001031 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001032 }
buzbee2a475e72011-09-07 17:19:17 -07001033#ifdef DISPLAY_MISSING_TARGETS
1034 genShowTarget(cUnit);
1035#endif
buzbeeec5adf32011-09-11 15:25:43 -07001036 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001037}
1038
buzbeeed3e9302011-09-23 17:34:19 -07001039STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001040{
1041 DecodedInstruction* dInsn = &mir->dalvikInsn;
1042 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001043 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001044 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1045 Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -07001046 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001047 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee7b1b86d2011-08-26 18:59:10 -07001048
buzbee109bd6a2011-09-06 13:58:41 -07001049 // Explicit register usage
1050 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001051 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001052 // Slow path
1053 nextCallInsn = nextVCallInsnSP;
1054 // If we need a slow-path callout, we'll restart here
1055 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1056 rollback->defMask = -1;
1057 } else {
1058 // Fast path
1059 nextCallInsn = nextVCallInsn;
1060 rollback = NULL;
1061 }
buzbee67bf8852011-08-17 17:51:35 -07001062 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001063 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001064 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001065 else
buzbeec0ecd652011-09-25 18:11:54 -07001066 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001067 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001068 // Finish up any of the call sequence not interleaved in arg loading
1069 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001070 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001071 }
buzbee2a475e72011-09-07 17:19:17 -07001072#ifdef DISPLAY_MISSING_TARGETS
1073 genShowTarget(cUnit);
1074#endif
buzbeeec5adf32011-09-11 15:25:43 -07001075 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001076}
1077
buzbeeed3e9302011-09-23 17:34:19 -07001078STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001079 BasicBlock* bb, ArmLIR* labelList)
1080{
1081 bool res = false; // Assume success
1082 RegLocation rlSrc[3];
1083 RegLocation rlDest = badLoc;
1084 RegLocation rlResult = badLoc;
1085 Opcode opcode = mir->dalvikInsn.opcode;
1086
1087 /* Prep Src and Dest locations */
1088 int nextSreg = 0;
1089 int nextLoc = 0;
1090 int attrs = oatDataFlowAttributes[opcode];
1091 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1092 if (attrs & DF_UA) {
1093 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1094 nextSreg++;
1095 } else if (attrs & DF_UA_WIDE) {
1096 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1097 nextSreg + 1);
1098 nextSreg+= 2;
1099 }
1100 if (attrs & DF_UB) {
1101 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1102 nextSreg++;
1103 } else if (attrs & DF_UB_WIDE) {
1104 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1105 nextSreg + 1);
1106 nextSreg+= 2;
1107 }
1108 if (attrs & DF_UC) {
1109 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1110 } else if (attrs & DF_UC_WIDE) {
1111 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1112 nextSreg + 1);
1113 }
1114 if (attrs & DF_DA) {
1115 rlDest = oatGetDest(cUnit, mir, 0);
1116 } else if (attrs & DF_DA_WIDE) {
1117 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1118 }
1119
1120 switch(opcode) {
1121 case OP_NOP:
1122 break;
1123
1124 case OP_MOVE_EXCEPTION:
1125 int exOffset;
1126 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001127 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001128 resetReg = oatAllocTemp(cUnit);
1129 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1130 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1131 loadConstant(cUnit, resetReg, 0);
1132 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1133 storeValue(cUnit, rlDest, rlResult);
1134 break;
1135
1136 case OP_RETURN_VOID:
buzbeec0ecd652011-09-25 18:11:54 -07001137 genSuspendPoll(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001138 break;
1139
1140 case OP_RETURN:
1141 case OP_RETURN_OBJECT:
buzbeec1f45042011-09-21 16:03:19 -07001142 genSuspendPoll(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001143 storeValue(cUnit, retLoc, rlSrc[0]);
1144 break;
1145
1146 case OP_RETURN_WIDE:
buzbeec1f45042011-09-21 16:03:19 -07001147 genSuspendPoll(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001148 rlDest = retLocWide;
1149 rlDest.fp = rlSrc[0].fp;
1150 storeValueWide(cUnit, rlDest, rlSrc[0]);
1151 break;
1152
1153 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001154 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001155 break; // Nop - combined w/ previous invoke
1156 /*
1157 * Somewhat hacky here. Because we're now passing
1158 * return values in registers, we have to let the
1159 * register allocation utilities know that the return
1160 * registers are live and may not be used for address
1161 * formation in storeValueWide.
1162 */
buzbeeed3e9302011-09-23 17:34:19 -07001163 DCHECK(retLocWide.lowReg == r0);
1164 DCHECK(retLocWide.highReg == r1);
buzbee67bf8852011-08-17 17:51:35 -07001165 oatLockTemp(cUnit, retLocWide.lowReg);
1166 oatLockTemp(cUnit, retLocWide.highReg);
1167 storeValueWide(cUnit, rlDest, retLocWide);
1168 oatFreeTemp(cUnit, retLocWide.lowReg);
1169 oatFreeTemp(cUnit, retLocWide.highReg);
1170 break;
1171
1172 case OP_MOVE_RESULT:
1173 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001174 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001175 break; // Nop - combined w/ previous invoke
1176 /* See comment for OP_MOVE_RESULT_WIDE */
buzbeeed3e9302011-09-23 17:34:19 -07001177 DCHECK(retLoc.lowReg == r0);
buzbee67bf8852011-08-17 17:51:35 -07001178 oatLockTemp(cUnit, retLoc.lowReg);
1179 storeValue(cUnit, rlDest, retLoc);
1180 oatFreeTemp(cUnit, retLoc.lowReg);
1181 break;
1182
1183 case OP_MOVE:
1184 case OP_MOVE_OBJECT:
1185 case OP_MOVE_16:
1186 case OP_MOVE_OBJECT_16:
1187 case OP_MOVE_FROM16:
1188 case OP_MOVE_OBJECT_FROM16:
1189 storeValue(cUnit, rlDest, rlSrc[0]);
1190 break;
1191
1192 case OP_MOVE_WIDE:
1193 case OP_MOVE_WIDE_16:
1194 case OP_MOVE_WIDE_FROM16:
1195 storeValueWide(cUnit, rlDest, rlSrc[0]);
1196 break;
1197
1198 case OP_CONST:
1199 case OP_CONST_4:
1200 case OP_CONST_16:
1201 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1202 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1203 storeValue(cUnit, rlDest, rlResult);
1204 break;
1205
1206 case OP_CONST_HIGH16:
1207 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1208 loadConstantNoClobber(cUnit, rlResult.lowReg,
1209 mir->dalvikInsn.vB << 16);
1210 storeValue(cUnit, rlDest, rlResult);
1211 break;
1212
1213 case OP_CONST_WIDE_16:
1214 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001215 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1216 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1217 mir->dalvikInsn.vB,
1218 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001219 storeValueWide(cUnit, rlDest, rlResult);
1220 break;
1221
1222 case OP_CONST_WIDE:
1223 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1224 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001225 mir->dalvikInsn.vB_wide & 0xffffffff,
1226 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001227 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001228 break;
1229
1230 case OP_CONST_WIDE_HIGH16:
1231 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1232 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1233 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001234 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001235 break;
1236
1237 case OP_MONITOR_ENTER:
1238 genMonitorEnter(cUnit, mir, rlSrc[0]);
1239 break;
1240
1241 case OP_MONITOR_EXIT:
1242 genMonitorExit(cUnit, mir, rlSrc[0]);
1243 break;
1244
1245 case OP_CHECK_CAST:
1246 genCheckCast(cUnit, mir, rlSrc[0]);
1247 break;
1248
1249 case OP_INSTANCE_OF:
1250 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1251 break;
1252
1253 case OP_NEW_INSTANCE:
1254 genNewInstance(cUnit, mir, rlDest);
1255 break;
1256
1257 case OP_THROW:
1258 genThrow(cUnit, mir, rlSrc[0]);
1259 break;
1260
buzbee5ade1d22011-09-09 14:44:52 -07001261 case OP_THROW_VERIFICATION_ERROR:
1262 loadWordDisp(cUnit, rSELF,
1263 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1264 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1265 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001266 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001267 break;
1268
buzbee67bf8852011-08-17 17:51:35 -07001269 case OP_ARRAY_LENGTH:
1270 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001271 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001272 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001273 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001274 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1275 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1276 rlResult.lowReg);
1277 storeValue(cUnit, rlDest, rlResult);
1278 break;
1279
1280 case OP_CONST_STRING:
1281 case OP_CONST_STRING_JUMBO:
1282 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1283 break;
1284
1285 case OP_CONST_CLASS:
1286 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1287 break;
1288
1289 case OP_FILL_ARRAY_DATA:
1290 genFillArrayData(cUnit, mir, rlSrc[0]);
1291 break;
1292
1293 case OP_FILLED_NEW_ARRAY:
1294 genFilledNewArray(cUnit, mir, false /* not range */);
1295 break;
1296
1297 case OP_FILLED_NEW_ARRAY_RANGE:
1298 genFilledNewArray(cUnit, mir, true /* range */);
1299 break;
1300
1301 case OP_NEW_ARRAY:
1302 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1303 break;
1304
1305 case OP_GOTO:
1306 case OP_GOTO_16:
1307 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001308 if (bb->taken->startOffset <= mir->offset) {
1309 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001310 }
1311 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1312 break;
1313
1314 case OP_PACKED_SWITCH:
1315 genPackedSwitch(cUnit, mir, rlSrc[0]);
1316 break;
1317
1318 case OP_SPARSE_SWITCH:
1319 genSparseSwitch(cUnit, mir, rlSrc[0]);
1320 break;
1321
1322 case OP_CMPL_FLOAT:
1323 case OP_CMPG_FLOAT:
1324 case OP_CMPL_DOUBLE:
1325 case OP_CMPG_DOUBLE:
1326 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1327 break;
1328
1329 case OP_CMP_LONG:
1330 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1331 break;
1332
1333 case OP_IF_EQ:
1334 case OP_IF_NE:
1335 case OP_IF_LT:
1336 case OP_IF_GE:
1337 case OP_IF_GT:
1338 case OP_IF_LE: {
1339 bool backwardBranch;
1340 ArmConditionCode cond;
1341 backwardBranch = (bb->taken->startOffset <= mir->offset);
1342 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001343 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001344 }
1345 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1346 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1347 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1348 switch(opcode) {
1349 case OP_IF_EQ:
1350 cond = kArmCondEq;
1351 break;
1352 case OP_IF_NE:
1353 cond = kArmCondNe;
1354 break;
1355 case OP_IF_LT:
1356 cond = kArmCondLt;
1357 break;
1358 case OP_IF_GE:
1359 cond = kArmCondGe;
1360 break;
1361 case OP_IF_GT:
1362 cond = kArmCondGt;
1363 break;
1364 case OP_IF_LE:
1365 cond = kArmCondLe;
1366 break;
1367 default:
1368 cond = (ArmConditionCode)0;
1369 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1370 }
1371 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1372 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1373 break;
1374 }
1375
1376 case OP_IF_EQZ:
1377 case OP_IF_NEZ:
1378 case OP_IF_LTZ:
1379 case OP_IF_GEZ:
1380 case OP_IF_GTZ:
1381 case OP_IF_LEZ: {
1382 bool backwardBranch;
1383 ArmConditionCode cond;
1384 backwardBranch = (bb->taken->startOffset <= mir->offset);
1385 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001386 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001387 }
1388 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1389 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1390 switch(opcode) {
1391 case OP_IF_EQZ:
1392 cond = kArmCondEq;
1393 break;
1394 case OP_IF_NEZ:
1395 cond = kArmCondNe;
1396 break;
1397 case OP_IF_LTZ:
1398 cond = kArmCondLt;
1399 break;
1400 case OP_IF_GEZ:
1401 cond = kArmCondGe;
1402 break;
1403 case OP_IF_GTZ:
1404 cond = kArmCondGt;
1405 break;
1406 case OP_IF_LEZ:
1407 cond = kArmCondLe;
1408 break;
1409 default:
1410 cond = (ArmConditionCode)0;
1411 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1412 }
1413 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1414 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1415 break;
1416 }
1417
1418 case OP_AGET_WIDE:
1419 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1420 break;
1421 case OP_AGET:
1422 case OP_AGET_OBJECT:
1423 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1424 break;
1425 case OP_AGET_BOOLEAN:
1426 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1427 rlDest, 0);
1428 break;
1429 case OP_AGET_BYTE:
1430 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1431 break;
1432 case OP_AGET_CHAR:
1433 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1434 rlDest, 1);
1435 break;
1436 case OP_AGET_SHORT:
1437 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1438 break;
1439 case OP_APUT_WIDE:
1440 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1441 break;
1442 case OP_APUT:
1443 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1444 break;
1445 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001446 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001447 break;
1448 case OP_APUT_SHORT:
1449 case OP_APUT_CHAR:
1450 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1451 rlSrc[0], 1);
1452 break;
1453 case OP_APUT_BYTE:
1454 case OP_APUT_BOOLEAN:
1455 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1456 rlSrc[0], 0);
1457 break;
1458
1459 case OP_IGET_WIDE:
1460 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001461 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001462 break;
1463
1464 case OP_IGET:
1465 case OP_IGET_VOLATILE:
1466 case OP_IGET_OBJECT:
1467 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001468 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001469 break;
1470
1471 case OP_IGET_BOOLEAN:
1472 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001473 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001474 break;
1475
1476 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001477 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001478 break;
1479
1480 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001481 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001482 break;
1483
1484 case OP_IPUT_WIDE:
1485 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001486 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001487 break;
1488
1489 case OP_IPUT_OBJECT:
1490 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001491 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001492 break;
1493
1494 case OP_IPUT:
1495 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001496 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001497 break;
1498
1499 case OP_IPUT_BOOLEAN:
1500 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001501 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001502 break;
1503
1504 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001505 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001506 break;
1507
1508 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001509 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001510 break;
1511
1512 case OP_SGET:
1513 case OP_SGET_OBJECT:
1514 case OP_SGET_BOOLEAN:
1515 case OP_SGET_BYTE:
1516 case OP_SGET_CHAR:
1517 case OP_SGET_SHORT:
1518 genSget(cUnit, mir, rlResult, rlDest);
1519 break;
1520
1521 case OP_SGET_WIDE:
1522 genSgetWide(cUnit, mir, rlResult, rlDest);
1523 break;
1524
1525 case OP_SPUT:
1526 case OP_SPUT_OBJECT:
1527 case OP_SPUT_BOOLEAN:
1528 case OP_SPUT_BYTE:
1529 case OP_SPUT_CHAR:
1530 case OP_SPUT_SHORT:
1531 genSput(cUnit, mir, rlSrc[0]);
1532 break;
1533
1534 case OP_SPUT_WIDE:
1535 genSputWide(cUnit, mir, rlSrc[0]);
1536 break;
1537
1538 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001539 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1540 true /*range*/);
1541 break;
buzbee67bf8852011-08-17 17:51:35 -07001542 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001543 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1544 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001545 break;
1546
1547 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001548 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1549 false /*range*/);
1550 break;
buzbee67bf8852011-08-17 17:51:35 -07001551 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001552 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1553 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001554 break;
1555
1556 case OP_INVOKE_VIRTUAL:
1557 case OP_INVOKE_VIRTUAL_RANGE:
1558 genInvokeVirtual(cUnit, mir);
1559 break;
1560
1561 case OP_INVOKE_SUPER:
1562 case OP_INVOKE_SUPER_RANGE:
1563 genInvokeSuper(cUnit, mir);
1564 break;
1565
1566 case OP_INVOKE_INTERFACE:
1567 case OP_INVOKE_INTERFACE_RANGE:
1568 genInvokeInterface(cUnit, mir);
1569 break;
1570
1571 case OP_NEG_INT:
1572 case OP_NOT_INT:
1573 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1574 break;
1575
1576 case OP_NEG_LONG:
1577 case OP_NOT_LONG:
1578 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1579 break;
1580
1581 case OP_NEG_FLOAT:
1582 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1583 break;
1584
1585 case OP_NEG_DOUBLE:
1586 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1587 break;
1588
1589 case OP_INT_TO_LONG:
1590 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1591 if (rlSrc[0].location == kLocPhysReg) {
1592 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1593 } else {
1594 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1595 }
1596 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1597 rlResult.lowReg, 31);
1598 storeValueWide(cUnit, rlDest, rlResult);
1599 break;
1600
1601 case OP_LONG_TO_INT:
1602 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1603 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1604 storeValue(cUnit, rlDest, rlSrc[0]);
1605 break;
1606
1607 case OP_INT_TO_BYTE:
1608 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1609 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1610 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1611 storeValue(cUnit, rlDest, rlResult);
1612 break;
1613
1614 case OP_INT_TO_SHORT:
1615 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1616 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1617 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1618 storeValue(cUnit, rlDest, rlResult);
1619 break;
1620
1621 case OP_INT_TO_CHAR:
1622 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1623 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1624 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1625 storeValue(cUnit, rlDest, rlResult);
1626 break;
1627
1628 case OP_INT_TO_FLOAT:
1629 case OP_INT_TO_DOUBLE:
1630 case OP_LONG_TO_FLOAT:
1631 case OP_LONG_TO_DOUBLE:
1632 case OP_FLOAT_TO_INT:
1633 case OP_FLOAT_TO_LONG:
1634 case OP_FLOAT_TO_DOUBLE:
1635 case OP_DOUBLE_TO_INT:
1636 case OP_DOUBLE_TO_LONG:
1637 case OP_DOUBLE_TO_FLOAT:
1638 genConversion(cUnit, mir);
1639 break;
1640
1641 case OP_ADD_INT:
1642 case OP_SUB_INT:
1643 case OP_MUL_INT:
1644 case OP_DIV_INT:
1645 case OP_REM_INT:
1646 case OP_AND_INT:
1647 case OP_OR_INT:
1648 case OP_XOR_INT:
1649 case OP_SHL_INT:
1650 case OP_SHR_INT:
1651 case OP_USHR_INT:
1652 case OP_ADD_INT_2ADDR:
1653 case OP_SUB_INT_2ADDR:
1654 case OP_MUL_INT_2ADDR:
1655 case OP_DIV_INT_2ADDR:
1656 case OP_REM_INT_2ADDR:
1657 case OP_AND_INT_2ADDR:
1658 case OP_OR_INT_2ADDR:
1659 case OP_XOR_INT_2ADDR:
1660 case OP_SHL_INT_2ADDR:
1661 case OP_SHR_INT_2ADDR:
1662 case OP_USHR_INT_2ADDR:
1663 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1664 break;
1665
1666 case OP_ADD_LONG:
1667 case OP_SUB_LONG:
1668 case OP_MUL_LONG:
1669 case OP_DIV_LONG:
1670 case OP_REM_LONG:
1671 case OP_AND_LONG:
1672 case OP_OR_LONG:
1673 case OP_XOR_LONG:
1674 case OP_ADD_LONG_2ADDR:
1675 case OP_SUB_LONG_2ADDR:
1676 case OP_MUL_LONG_2ADDR:
1677 case OP_DIV_LONG_2ADDR:
1678 case OP_REM_LONG_2ADDR:
1679 case OP_AND_LONG_2ADDR:
1680 case OP_OR_LONG_2ADDR:
1681 case OP_XOR_LONG_2ADDR:
1682 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1683 break;
1684
buzbee67bf8852011-08-17 17:51:35 -07001685 case OP_SHL_LONG:
1686 case OP_SHR_LONG:
1687 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001688 case OP_SHL_LONG_2ADDR:
1689 case OP_SHR_LONG_2ADDR:
1690 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001691 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1692 break;
1693
1694 case OP_ADD_FLOAT:
1695 case OP_SUB_FLOAT:
1696 case OP_MUL_FLOAT:
1697 case OP_DIV_FLOAT:
1698 case OP_REM_FLOAT:
1699 case OP_ADD_FLOAT_2ADDR:
1700 case OP_SUB_FLOAT_2ADDR:
1701 case OP_MUL_FLOAT_2ADDR:
1702 case OP_DIV_FLOAT_2ADDR:
1703 case OP_REM_FLOAT_2ADDR:
1704 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1705 break;
1706
1707 case OP_ADD_DOUBLE:
1708 case OP_SUB_DOUBLE:
1709 case OP_MUL_DOUBLE:
1710 case OP_DIV_DOUBLE:
1711 case OP_REM_DOUBLE:
1712 case OP_ADD_DOUBLE_2ADDR:
1713 case OP_SUB_DOUBLE_2ADDR:
1714 case OP_MUL_DOUBLE_2ADDR:
1715 case OP_DIV_DOUBLE_2ADDR:
1716 case OP_REM_DOUBLE_2ADDR:
1717 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1718 break;
1719
1720 case OP_RSUB_INT:
1721 case OP_ADD_INT_LIT16:
1722 case OP_MUL_INT_LIT16:
1723 case OP_DIV_INT_LIT16:
1724 case OP_REM_INT_LIT16:
1725 case OP_AND_INT_LIT16:
1726 case OP_OR_INT_LIT16:
1727 case OP_XOR_INT_LIT16:
1728 case OP_ADD_INT_LIT8:
1729 case OP_RSUB_INT_LIT8:
1730 case OP_MUL_INT_LIT8:
1731 case OP_DIV_INT_LIT8:
1732 case OP_REM_INT_LIT8:
1733 case OP_AND_INT_LIT8:
1734 case OP_OR_INT_LIT8:
1735 case OP_XOR_INT_LIT8:
1736 case OP_SHL_INT_LIT8:
1737 case OP_SHR_INT_LIT8:
1738 case OP_USHR_INT_LIT8:
1739 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1740 break;
1741
1742 default:
1743 res = true;
1744 }
1745 return res;
1746}
1747
buzbeeed3e9302011-09-23 17:34:19 -07001748STATIC const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001749 "kMirOpPhi",
1750 "kMirOpNullNRangeUpCheck",
1751 "kMirOpNullNRangeDownCheck",
1752 "kMirOpLowerBound",
1753 "kMirOpPunt",
1754 "kMirOpCheckInlinePrediction",
1755};
1756
1757/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001758STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001759{
1760 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1761 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1762 strcpy(msg, extendedMIROpNames[opOffset]);
1763 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1764
1765 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1766 case kMirOpPhi: {
1767 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1768 op->flags.isNop = true;
1769 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1770 break;
1771 }
1772 default:
1773 break;
1774 }
1775}
1776
1777/* If there are any ins passed in registers that have not been promoted
1778 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001779 * Note: at this pointCopy any ins that are passed in register to their
1780 * home location */
buzbeeed3e9302011-09-23 17:34:19 -07001781STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001782{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001783 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001784 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001785 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1786 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001787 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001788 int startLoc = cUnit->method->NumRegisters() -
1789 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001790 for (int i = 0; i < inRegs; i++) {
1791 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001792 //TUNING: be smarter about flushing ins to frame
1793 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001794 if (loc.location == kLocPhysReg) {
1795 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001796 }
1797 }
1798
1799 // Handle special case of wide argument half in regs, half in frame
1800 if (inRegs == 3) {
1801 RegLocation loc = cUnit->regLocation[startLoc + 2];
1802 if (loc.wide && loc.location == kLocPhysReg) {
1803 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001804 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001805 inRegs++;
1806 }
1807 }
1808
1809 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001810 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001811 RegLocation loc = cUnit->regLocation[startLoc + i];
1812 if (loc.fpLocation == kLocPhysReg) {
1813 loc.location = kLocPhysReg;
1814 loc.fp = true;
1815 loc.lowReg = loc.fpLowReg;
1816 loc.highReg = loc.fpHighReg;
1817 }
1818 if (loc.location == kLocPhysReg) {
1819 if (loc.wide) {
buzbeeb29e4d12011-09-26 15:05:48 -07001820 if (loc.fp && (loc.lowReg & 1) != 0) {
1821 // Misaligned - need to load as a pair of singles
1822 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
1823 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
1824 } else {
1825 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1826 loc.lowReg, loc.highReg, INVALID_SREG);
1827 }
buzbee67bf8852011-08-17 17:51:35 -07001828 i++;
1829 } else {
buzbee561227c2011-09-02 15:28:19 -07001830 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001831 }
1832 }
1833 i++;
1834 }
1835}
1836
1837/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001838STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001839{
1840 MIR* mir;
1841 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1842 int blockId = bb->id;
1843
1844 cUnit->curBlock = bb;
1845 labelList[blockId].operands[0] = bb->startOffset;
1846
1847 /* Insert the block label */
1848 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1849 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1850
1851 oatClobberAllRegs(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}