blob: 7ea7d698c228e9f144012e7df7d0b446fcc64e5b [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
buzbeece302932011-10-04 14:32:18 -070017#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
18 (1 << kDebugDisplayMissingTargets))
Elliott Hughes1240dad2011-09-09 16:24:50 -070019
buzbee67bc2362011-10-11 18:08:40 -070020STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, INVALID_REG,
21 INVALID_REG, INVALID_SREG};
buzbee6181f792011-09-29 11:14:04 -070022
23/* Mark register usage state and return long retloc */
24STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
25{
26 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
27 oatLockTemp(cUnit, res.lowReg);
28 oatLockTemp(cUnit, res.highReg);
29 oatMarkPair(cUnit, res.lowReg, res.highReg);
30 return res;
31}
32
33STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
34{
35 RegLocation res = LOC_DALVIK_RETURN_VAL;
36 oatLockTemp(cUnit, res.lowReg);
37 return res;
38}
buzbee67bf8852011-08-17 17:51:35 -070039
buzbeedfd3d702011-08-28 12:56:51 -070040/*
41 * Let helper function take care of everything. Will call
42 * Array::AllocFromCode(type_idx, method, count);
43 * Note: AllocFromCode will handle checks for errNegativeArraySize.
44 */
buzbeeed3e9302011-09-23 17:34:19 -070045STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -070046 RegLocation rlSrc)
47{
buzbeedfd3d702011-08-28 12:56:51 -070048 oatFlushAllRegs(cUnit); /* Everything to home location */
49 loadWordDisp(cUnit, rSELF,
Elliott Hughesb408de72011-10-04 14:35:05 -070050 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070051 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
52 loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
53 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070054 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070055 RegLocation rlResult = oatGetReturn(cUnit);
56 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070057}
58
59/*
60 * Similar to genNewArray, but with post-allocation initialization.
61 * Verifier guarantees we're dealing with an array class. Current
62 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
63 * Current code also throws internal unimp if not 'L', '[' or 'I'.
64 */
buzbeeed3e9302011-09-23 17:34:19 -070065STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070066{
67 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070068 int elems = dInsn->vA;
69 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070070 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070071 loadWordDisp(cUnit, rSELF,
Elliott Hughesb408de72011-10-04 14:35:05 -070072 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070073 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
74 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
75 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070076 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070077 /*
buzbeedfd3d702011-08-28 12:56:51 -070078 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
79 * return region. Because AllocFromCode placed the new array
80 * in r0, we'll just lock it into place. When debugger support is
81 * added, it may be necessary to additionally copy all return
82 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070083 */
buzbee67bf8852011-08-17 17:51:35 -070084 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070085
buzbee67bf8852011-08-17 17:51:35 -070086 // Having a range of 0 is legal
87 if (isRange && (dInsn->vA > 0)) {
88 /*
89 * Bit of ugliness here. We're going generate a mem copy loop
90 * on the register range, but it is possible that some regs
91 * in the range have been promoted. This is unlikely, but
92 * before generating the copy, we'll just force a flush
93 * of any regs in the source range that have been promoted to
94 * home location.
95 */
96 for (unsigned int i = 0; i < dInsn->vA; i++) {
97 RegLocation loc = oatUpdateLoc(cUnit,
98 oatGetSrc(cUnit, mir, i));
99 if (loc.location == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -0700100 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
101 loc.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700102 }
103 }
104 /*
105 * TUNING note: generated code here could be much improved, but
106 * this is an uncommon operation and isn't especially performance
107 * critical.
108 */
109 int rSrc = oatAllocTemp(cUnit);
110 int rDst = oatAllocTemp(cUnit);
111 int rIdx = oatAllocTemp(cUnit);
112 int rVal = rLR; // Using a lot of temps, rLR is known free here
113 // Set up source pointer
114 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
buzbee67bc2362011-10-11 18:08:40 -0700115 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
116 oatSRegOffset(cUnit, rlFirst.sRegLow));
buzbee67bf8852011-08-17 17:51:35 -0700117 // Set up the target pointer
118 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700119 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700120 // Set up the loop counter (known to be > 0)
buzbee31813452011-10-16 14:33:08 -0700121 loadConstant(cUnit, rIdx, dInsn->vA - 1);
buzbee67bf8852011-08-17 17:51:35 -0700122 // Generate the copy loop. Going backwards for convenience
123 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
124 target->defMask = ENCODE_ALL;
125 // Copy next element
126 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
127 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
128 // Use setflags encoding here
129 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee31813452011-10-16 14:33:08 -0700130 ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
buzbee67bf8852011-08-17 17:51:35 -0700131 branch->generic.target = (LIR*)target;
132 } else if (!isRange) {
133 // TUNING: interleave
134 for (unsigned int i = 0; i < dInsn->vA; i++) {
135 RegLocation rlArg = loadValue(cUnit,
136 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700137 storeBaseDisp(cUnit, r0,
138 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700139 i * 4, rlArg.lowReg, kWord);
140 // If the loadValue caused a temp to be allocated, free it
141 if (oatIsTemp(cUnit, rlArg.lowReg)) {
142 oatFreeTemp(cUnit, rlArg.lowReg);
143 }
144 }
145 }
146}
147
Brian Carlstrom845490b2011-09-19 15:56:53 -0700148Field* FindFieldWithResolvedStaticStorage(const Method* method,
149 const uint32_t fieldIdx,
150 uint32_t& resolvedTypeIdx) {
151 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
152 Field* field = class_linker->ResolveField(fieldIdx, method, true);
153 if (field == NULL) {
154 return NULL;
155 }
156 const art::DexFile& dex_file = class_linker->
157 FindDexFile(method->GetDeclaringClass()->GetDexCache());
158 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
159 int type_idx = field_id.class_idx_;
160 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
161 // Check if storage class is the same as class referred to by type idx.
162 // They may not be if the FieldId refers a subclass, but storage is in super
163 if (field->GetDeclaringClass() == klass) {
164 resolvedTypeIdx = type_idx;
165 return field;
166 }
167 // See if we can find a dex reference for the storage class.
168 // we may not if the dex file never references the super class,
169 // but usually it will.
170 std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
171 for (size_t type_idx = 0; type_idx < dex_file.NumTypeIds(); type_idx++) {
172 const art::DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
173 if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
174 resolvedTypeIdx = type_idx;
175 return field;
176 }
177 }
178 return NULL; // resort to slow path
179}
180
buzbeeed3e9302011-09-23 17:34:19 -0700181STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700182{
buzbeee1931742011-08-28 21:15:53 -0700183 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
184 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700185 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700186 uint32_t typeIdx;
187 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700188 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700189 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700190 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700191 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700192 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
193 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700194 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
195 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
196 loadCurrMethodDirect(cUnit, r1);
197 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700198 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700199 } else {
buzbee1da522d2011-09-04 11:22:20 -0700200 // fast path
201 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700202 // Using fixed register to sync with slow path
203 int rMethod = r1;
204 oatLockTemp(cUnit, rMethod);
205 loadCurrMethodDirect(cUnit, rMethod);
206 int rBase = r0;
207 oatLockTemp(cUnit, rBase);
208 loadWordDisp(cUnit, rMethod,
209 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
210 rBase);
211 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
212 sizeof(int32_t*)* typeIdx, rBase);
213 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700214 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700215 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
216 loadWordDisp(cUnit, rSELF,
217 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
218 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700219 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700220 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
221 skipTarget->defMask = ENCODE_ALL;
222 branchOver->generic.target = (LIR*)skipTarget;
223 rlSrc = oatGetSrc(cUnit, mir, 0);
224 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700225#if ANDROID_SMP != 0
226 if (field->IsVolatile()) {
227 oatGenMemBarrier(cUnit, kST);
228 }
229#endif
buzbee1da522d2011-09-04 11:22:20 -0700230 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700231#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700232 if (field->IsVolatile()) {
233 oatGenMemBarrier(cUnit, kSY);
234 }
buzbee67bf8852011-08-17 17:51:35 -0700235#endif
buzbee1da522d2011-09-04 11:22:20 -0700236 if (isObject) {
237 markGCCard(cUnit, rlSrc.lowReg, rBase);
238 }
239 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700240 }
buzbee67bf8852011-08-17 17:51:35 -0700241}
242
buzbeeed3e9302011-09-23 17:34:19 -0700243STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700244{
buzbee1da522d2011-09-04 11:22:20 -0700245 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700246 uint32_t typeIdx;
247 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700248 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700249#if ANDROID_SMP != 0
250 bool isVolatile = (field == NULL) || field->IsVolatile();
251#else
252 bool isVolatile = false;
253#endif
254 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700255 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700256 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700257 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
258 loadCurrMethodDirect(cUnit, r1);
259 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700260 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700261 } else {
buzbee1da522d2011-09-04 11:22:20 -0700262 // fast path
263 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700264 // Using fixed register to sync with slow path
265 int rMethod = r1;
266 oatLockTemp(cUnit, rMethod);
267 loadCurrMethodDirect(cUnit, r1);
268 int rBase = r0;
269 oatLockTemp(cUnit, rBase);
270 loadWordDisp(cUnit, rMethod,
271 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
272 rBase);
273 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
274 sizeof(int32_t*)* typeIdx, rBase);
275 // TUNING: fast path should fall through
276 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
277 loadWordDisp(cUnit, rSELF,
278 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
279 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700280 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700281 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
282 skipTarget->defMask = ENCODE_ALL;
283 branchOver->generic.target = (LIR*)skipTarget;
284 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
285 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
286 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
287 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700288 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700289 }
buzbee67bf8852011-08-17 17:51:35 -0700290}
291
292
buzbeeed3e9302011-09-23 17:34:19 -0700293STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700294 RegLocation rlResult, RegLocation rlDest)
295{
buzbee1da522d2011-09-04 11:22:20 -0700296 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700297 uint32_t typeIdx;
298 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700299#if ANDROID_SMP != 0
300 bool isVolatile = (field == NULL) || field->IsVolatile();
301#else
302 bool isVolatile = false;
303#endif
buzbee6181f792011-09-29 11:14:04 -0700304 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700305 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700306 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700307 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700308 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
309 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700310 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700311 RegLocation rlResult = oatGetReturnWide(cUnit);
312 storeValueWide(cUnit, rlDest, rlResult);
313 } else {
buzbee1da522d2011-09-04 11:22:20 -0700314 // Fast path
315 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700316 // Using fixed register to sync with slow path
317 int rMethod = r1;
318 oatLockTemp(cUnit, rMethod);
319 loadCurrMethodDirect(cUnit, rMethod);
320 int rBase = r0;
321 oatLockTemp(cUnit, rBase);
322 loadWordDisp(cUnit, rMethod,
323 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
324 rBase);
325 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
326 sizeof(int32_t*)* typeIdx, rBase);
327 // TUNING: fast path should fall through
328 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
329 loadWordDisp(cUnit, rSELF,
330 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
331 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700332 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700333 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
334 skipTarget->defMask = ENCODE_ALL;
335 branchOver->generic.target = (LIR*)skipTarget;
336 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
337 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700338 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
339 rlResult.highReg, INVALID_SREG);
340 oatFreeTemp(cUnit, rBase);
341 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700342 }
buzbee67bf8852011-08-17 17:51:35 -0700343}
344
buzbeeed3e9302011-09-23 17:34:19 -0700345STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700346 RegLocation rlResult, RegLocation rlDest)
347{
buzbee1da522d2011-09-04 11:22:20 -0700348 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700349 uint32_t typeIdx;
350 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700351 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
352 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700353 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700354 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700355 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700356 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700357 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
358 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700359 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
360 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
361 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700362 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700363 RegLocation rlResult = oatGetReturn(cUnit);
364 storeValue(cUnit, rlDest, rlResult);
365 } else {
buzbee1da522d2011-09-04 11:22:20 -0700366 // Fast path
367 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700368 // Using fixed register to sync with slow path
369 int rMethod = r1;
370 oatLockTemp(cUnit, rMethod);
371 loadCurrMethodDirect(cUnit, rMethod);
372 int rBase = r0;
373 oatLockTemp(cUnit, rBase);
374 loadWordDisp(cUnit, rMethod,
375 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
376 rBase);
377 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
378 sizeof(int32_t*)* typeIdx, rBase);
379 // TUNING: fast path should fall through
380 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
381 loadWordDisp(cUnit, rSELF,
382 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
383 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700384 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700385 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
386 skipTarget->defMask = ENCODE_ALL;
387 branchOver->generic.target = (LIR*)skipTarget;
388 rlDest = oatGetDest(cUnit, mir, 0);
389 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700390#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700391 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700392 oatGenMemBarrier(cUnit, kSY);
393 }
buzbee67bf8852011-08-17 17:51:35 -0700394#endif
buzbee1da522d2011-09-04 11:22:20 -0700395 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
396 oatFreeTemp(cUnit, rBase);
397 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700398 }
buzbee67bf8852011-08-17 17:51:35 -0700399}
400
buzbee561227c2011-09-02 15:28:19 -0700401typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
402 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700403
404/*
405 * Bit of a hack here - in leiu of a real scheduling pass,
406 * emit the next instruction in static & direct invoke sequences.
407 */
buzbeeed3e9302011-09-23 17:34:19 -0700408STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700409 DecodedInstruction* dInsn, int state,
410 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700411{
buzbee561227c2011-09-02 15:28:19 -0700412 DCHECK(rollback == NULL);
413 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700414 switch(state) {
415 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700416 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700417 break;
buzbee561227c2011-09-02 15:28:19 -0700418 case 1: // Get method->code_and_direct_methods_
419 loadWordDisp(cUnit, r0,
420 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
421 r0);
buzbee67bf8852011-08-17 17:51:35 -0700422 break;
buzbee561227c2011-09-02 15:28:19 -0700423 case 2: // Grab target method* and target code_
424 loadWordDisp(cUnit, r0,
425 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
426 loadWordDisp(cUnit, r0,
427 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700428 break;
429 default:
430 return -1;
431 }
432 return state + 1;
433}
434
buzbee67bf8852011-08-17 17:51:35 -0700435/*
436 * Bit of a hack here - in leiu of a real scheduling pass,
437 * emit the next instruction in a virtual invoke sequence.
438 * We can use rLR as a temp prior to target address loading
439 * Note also that we'll load the first argument ("this") into
440 * r1 here rather than the standard loadArgRegs.
441 */
buzbeeed3e9302011-09-23 17:34:19 -0700442STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700443 DecodedInstruction* dInsn, int state,
444 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700445{
buzbee561227c2011-09-02 15:28:19 -0700446 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700447 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700448 /*
449 * This is the fast path in which the target virtual method is
450 * fully resolved at compile time.
451 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700452 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
453 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -0700454 CHECK(baseMethod != NULL);
455 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700456 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700457 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700458 rlArg = oatGetSrc(cUnit, mir, 0);
459 loadValueDirectFixed(cUnit, rlArg, r1);
460 break;
buzbee561227c2011-09-02 15:28:19 -0700461 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700462 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700463 // get this->klass_ [use r1, set rLR]
464 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700465 break;
buzbee561227c2011-09-02 15:28:19 -0700466 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
467 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700468 break;
buzbee561227c2011-09-02 15:28:19 -0700469 case 3: // Get target method [use rLR, set r0]
470 loadWordDisp(cUnit, rLR, (target_idx * 4) +
471 art::Array::DataOffset().Int32Value(), r0);
472 break;
473 case 4: // Get the target compiled code address [uses r0, sets rLR]
474 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700475 break;
476 default:
477 return -1;
478 }
479 return state + 1;
480}
481
buzbeeed3e9302011-09-23 17:34:19 -0700482STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700483 DecodedInstruction* dInsn, int state,
484 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700485{
486 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700487 ArmLIR* skipBranch;
488 ArmLIR* skipTarget;
489 /*
490 * This handles the case in which the base method is not fully
491 * resolved at compile time. We must generate code to test
492 * for resolution a run time, bail to the slow path if not to
493 * fill in all the tables. In the latter case, we'll restart at
494 * at the beginning of the sequence.
495 */
buzbee7b1b86d2011-08-26 18:59:10 -0700496 switch(state) {
497 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700498 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700499 break;
buzbee561227c2011-09-02 15:28:19 -0700500 case 1: // Get method->dex_cache_resolved_methods_
501 loadWordDisp(cUnit, r0,
502 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700503 break;
buzbee561227c2011-09-02 15:28:19 -0700504 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
505 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
506 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700507 break;
buzbee561227c2011-09-02 15:28:19 -0700508 case 3: // Resolved?
509 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
510 // Slowest path, bail to helper, rollback and retry
511 loadWordDisp(cUnit, rSELF,
512 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
513 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700514 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700515 genUnconditionalBranch(cUnit, rollback);
516 // Resume normal slow path
517 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
518 skipTarget->defMask = ENCODE_ALL;
519 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700520 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700521 loadBaseDisp(cUnit, mir, rLR,
522 Method::GetMethodIndexOffset().Int32Value(), r0,
523 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700524 // Load "this" [set r1]
525 rlArg = oatGetSrc(cUnit, mir, 0);
526 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700527 break;
528 case 4:
529 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700530 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700531 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700532 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700533 break;
buzbee561227c2011-09-02 15:28:19 -0700534 case 5:
535 // get this->klass_->vtable_ [usr rLR, set rLR]
536 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700537 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700538 // In load shadow fold vtable_ object header size into method_index_
539 opRegImm(cUnit, kOpAdd, r0,
540 art::Array::DataOffset().Int32Value() / 4);
541 // Get target Method*
542 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
543 break;
544 case 6: // Get the target compiled code address [uses r0, sets rLR]
545 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700546 break;
547 default:
548 return -1;
549 }
550 return state + 1;
551}
552
buzbeeed3e9302011-09-23 17:34:19 -0700553STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700554 DecodedInstruction* dInsn, int callState,
555 NextCallInsn nextCallInsn, ArmLIR* rollback,
556 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700557{
buzbeec0ecd652011-09-25 18:11:54 -0700558 int nextReg = r1;
559 int nextArg = 0;
560 if (skipThis) {
561 nextReg++;
562 nextArg++;
563 }
564 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
565 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
566 rlArg = oatUpdateRawLoc(cUnit, rlArg);
567 if (rlArg.wide && (nextReg <= r2)) {
568 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
569 nextReg++;
570 nextArg++;
571 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700572 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700573 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700574 }
buzbeec0ecd652011-09-25 18:11:54 -0700575 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700576 }
577 return callState;
578}
579
buzbee4a3164f2011-09-03 11:25:10 -0700580// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700581STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700582 DecodedInstruction* dInsn, int state,
583 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700584{
buzbee510c6052011-10-27 10:47:20 -0700585 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700586 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700587 case 0: // Load trampoline target
588 loadWordDisp(cUnit, rSELF,
589 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
590 rLR);
591 // Load r0 with method index
592 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700593 break;
buzbee67bf8852011-08-17 17:51:35 -0700594 default:
595 return -1;
596 }
597 return state + 1;
598}
599
buzbee67bf8852011-08-17 17:51:35 -0700600/*
601 * Interleave launch code for INVOKE_SUPER. See comments
602 * for nextVCallIns.
603 */
buzbeeed3e9302011-09-23 17:34:19 -0700604STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700605 DecodedInstruction* dInsn, int state,
606 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700607{
buzbee4a3164f2011-09-03 11:25:10 -0700608 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700609 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700610 /*
611 * This is the fast path in which the target virtual method is
612 * fully resolved at compile time. Note also that this path assumes
613 * that the check to verify that the target method index falls
614 * within the size of the super's vtable has been done at compile-time.
615 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700616 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
617 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700618 CHECK(baseMethod != NULL);
619 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
620 CHECK(superClass != NULL);
621 int32_t target_idx = baseMethod->GetMethodIndex();
622 CHECK(superClass->GetVTable()->GetLength() > target_idx);
623 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
624 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700625 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700626 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700627 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700628 // Load "this" [set r1]
629 rlArg = oatGetSrc(cUnit, mir, 0);
630 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700631 // Get method->declaring_class_ [use r0, set rLR]
632 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
633 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700634 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700635 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700636 break;
637 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
638 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
639 rLR);
640 break;
641 case 2: // Get ...->super_class_->vtable [u/s rLR]
642 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
643 break;
644 case 3: // Get target method [use rLR, set r0]
645 loadWordDisp(cUnit, rLR, (target_idx * 4) +
646 art::Array::DataOffset().Int32Value(), r0);
647 break;
648 case 4: // Get the target compiled code address [uses r0, sets rLR]
649 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
650 break;
buzbee67bf8852011-08-17 17:51:35 -0700651 default:
652 return -1;
653 }
buzbee4a3164f2011-09-03 11:25:10 -0700654 return state + 1;
655}
656
657/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700658STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700659 DecodedInstruction* dInsn, int state,
660 ArmLIR* rollback)
661{
buzbee4a3164f2011-09-03 11:25:10 -0700662 RegLocation rlArg;
663 ArmLIR* skipBranch;
664 ArmLIR* skipTarget;
665 int tReg;
666 /*
667 * This handles the case in which the base method is not fully
668 * resolved at compile time. We must generate code to test
669 * for resolution a run time, bail to the slow path if not to
670 * fill in all the tables. In the latter case, we'll restart at
671 * at the beginning of the sequence.
672 */
673 switch(state) {
674 case 0: // Get the current Method* [sets r0]
675 loadCurrMethodDirect(cUnit, r0);
676 break;
677 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
678 loadWordDisp(cUnit, r0,
679 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
680 break;
681 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
682 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
683 art::Array::DataOffset().Int32Value(), rLR);
684 break;
685 case 3: // Resolved?
686 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
687 // Slowest path, bail to helper, rollback and retry
688 loadWordDisp(cUnit, rSELF,
689 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
690 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700691 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700692 genUnconditionalBranch(cUnit, rollback);
693 // Resume normal slow path
694 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
695 skipTarget->defMask = ENCODE_ALL;
696 skipBranch->generic.target = (LIR*)skipTarget;
697 // Get base_method->method_index [usr rLR, set rLR]
698 loadBaseDisp(cUnit, mir, rLR,
699 Method::GetMethodIndexOffset().Int32Value(), rLR,
700 kUnsignedHalf, INVALID_SREG);
701 // Load "this" [set r1]
702 rlArg = oatGetSrc(cUnit, mir, 0);
703 loadValueDirectFixed(cUnit, rlArg, r1);
704 // Load curMethod->declaring_class_ [uses r0, sets r0]
705 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
706 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700707 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700708 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700709 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700710 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
711 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700712 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700713 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700714 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700715 // Range check, throw NSM on failure
716 tReg = oatAllocTemp(cUnit);
717 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
718 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700719 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
720 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700721 oatFreeTemp(cUnit, tReg);
722 }
buzbee6a0f7f52011-09-05 16:14:20 -0700723 // Adjust vtable_ base past object header
724 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700725 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700726 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700727 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700728 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700729 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
730 break;
731 default:
732 return -1;
733 }
buzbee67bf8852011-08-17 17:51:35 -0700734 return state + 1;
735}
736
737/*
738 * Load up to 5 arguments, the first three of which will be in
739 * r1 .. r3. On entry r0 contains the current method pointer,
740 * and as part of the load sequence, it must be replaced with
741 * the target method pointer. Note, this may also be called
742 * for "range" variants if the number of arguments is 5 or fewer.
743 */
buzbeeed3e9302011-09-23 17:34:19 -0700744STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700745 DecodedInstruction* dInsn, int callState,
746 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700747 NextCallInsn nextCallInsn, ArmLIR* rollback,
748 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700749{
750 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700751
752 /* If no arguments, just return */
753 if (dInsn->vA == 0)
754 return callState;
755
buzbee561227c2011-09-02 15:28:19 -0700756 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700757
buzbeec0ecd652011-09-25 18:11:54 -0700758 DCHECK_LE(dInsn->vA, 5U);
759 if (dInsn->vA > 3) {
760 uint32_t nextUse = 3;
761 //Detect special case of wide arg spanning arg3/arg4
762 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
763 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
764 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
765 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
766 rlUse2.wide) {
767 int reg;
768 // Wide spans, we need the 2nd half of uses[2].
769 rlArg = oatUpdateLocWide(cUnit, rlUse2);
770 if (rlArg.location == kLocPhysReg) {
771 reg = rlArg.highReg;
772 } else {
773 // r2 & r3 can safely be used here
774 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700775 loadWordDisp(cUnit, rSP,
776 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
buzbeec0ecd652011-09-25 18:11:54 -0700777 callState = nextCallInsn(cUnit, mir, dInsn, callState,
778 rollback);
779 }
780 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
781 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
782 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
783 nextUse++;
784 }
785 // Loop through the rest
786 while (nextUse < dInsn->vA) {
787 int lowReg;
788 int highReg;
789 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
790 rlArg = oatUpdateRawLoc(cUnit, rlArg);
791 if (rlArg.location == kLocPhysReg) {
792 lowReg = rlArg.lowReg;
793 highReg = rlArg.highReg;
794 } else {
795 lowReg = r2;
796 highReg = r3;
797 if (rlArg.wide) {
798 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
799 } else {
800 loadValueDirectFixed(cUnit, rlArg, lowReg);
801 }
802 callState = nextCallInsn(cUnit, mir, dInsn, callState,
803 rollback);
804 }
805 int outsOffset = (nextUse + 1) * 4;
806 if (rlArg.wide) {
807 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
808 nextUse += 2;
809 } else {
810 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
811 nextUse++;
812 }
buzbee561227c2011-09-02 15:28:19 -0700813 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700814 }
buzbee67bf8852011-08-17 17:51:35 -0700815 }
816
buzbeec0ecd652011-09-25 18:11:54 -0700817 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
818 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700819
buzbee67bf8852011-08-17 17:51:35 -0700820 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700821 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700822 }
823 return callState;
824}
825
826/*
827 * May have 0+ arguments (also used for jumbo). Note that
828 * source virtual registers may be in physical registers, so may
829 * need to be flushed to home location before copying. This
830 * applies to arg3 and above (see below).
831 *
832 * Two general strategies:
833 * If < 20 arguments
834 * Pass args 3-18 using vldm/vstm block copy
835 * Pass arg0, arg1 & arg2 in r1-r3
836 * If 20+ arguments
837 * Pass args arg19+ using memcpy block copy
838 * Pass arg0, arg1 & arg2 in r1-r3
839 *
840 */
buzbeeed3e9302011-09-23 17:34:19 -0700841STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700842 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700843 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700844 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700845{
846 int firstArg = dInsn->vC;
847 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700848
buzbee67bf8852011-08-17 17:51:35 -0700849 // If we can treat it as non-range (Jumbo ops will use range form)
850 if (numArgs <= 5)
851 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700852 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700853 /*
854 * Make sure range list doesn't span the break between in normal
855 * Dalvik vRegs and the ins.
856 */
buzbee1b4c8592011-08-31 10:43:51 -0700857 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700858 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700859 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
860 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700861 }
862
863 /*
864 * First load the non-register arguments. Both forms expect all
865 * of the source arguments to be in their home frame location, so
866 * scan the sReg names and flush any that have been promoted to
867 * frame backing storage.
868 */
869 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700870 for (int nextArg = 0; nextArg < numArgs;) {
871 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700872 if (loc.wide) {
873 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700874 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700875 storeBaseDispWide(cUnit, rSP,
876 oatSRegOffset(cUnit, loc.sRegLow),
877 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700878 }
buzbeec0ecd652011-09-25 18:11:54 -0700879 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700880 } else {
881 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700882 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700883 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
884 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700885 }
buzbeec0ecd652011-09-25 18:11:54 -0700886 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700887 }
888 }
889
buzbee67bc2362011-10-11 18:08:40 -0700890 int startOffset = oatSRegOffset(cUnit,
891 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700892 int outsOffset = 4 /* Method* */ + (3 * 4);
893 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700894 // Generate memcpy
895 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
896 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700897 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
898 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700899 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700900 // Restore Method*
901 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700902 } else {
903 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700904 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700905 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700906 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700907 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
908 //TUNING: loosen barrier
909 ld->defMask = ENCODE_ALL;
910 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700911 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700912 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700913 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700914 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
915 setMemRefType(st, false /* isLoad */, kDalvikReg);
916 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700917 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700918 }
919
buzbeec0ecd652011-09-25 18:11:54 -0700920 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
921 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700922
buzbee561227c2011-09-02 15:28:19 -0700923 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee99f27232011-10-05 12:56:36 -0700924 if (pcrLabel) {
925 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
926 }
buzbee67bf8852011-08-17 17:51:35 -0700927 return callState;
928}
929
buzbee2a475e72011-09-07 17:19:17 -0700930// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700931STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700932{
933 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
934 loadWordDisp(cUnit, rSELF,
935 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
936 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
937 target->defMask = -1;
938 branchOver->generic.target = (LIR*)target;
939}
buzbee2a475e72011-09-07 17:19:17 -0700940
buzbeeed3e9302011-09-23 17:34:19 -0700941STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700942 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700943{
944 DecodedInstruction* dInsn = &mir->dalvikInsn;
945 int callState = 0;
946 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700947 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700948 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700949 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700950
buzbee109bd6a2011-09-06 13:58:41 -0700951 // Explicit register usage
952 oatLockCallTemps(cUnit);
953
buzbee99f27232011-10-05 12:56:36 -0700954 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
955 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
956 int idx = mir->dalvikInsn.vB;
957 Method* target = cUnit->method->GetDexCacheResolvedMethods()->Get(idx);
958 if (target) {
959 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
960 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
961 loadValueDirectFixed(cUnit, rlArg, r0);
962 loadWordDisp(cUnit, rSELF,
963 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
964 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
965 opReg(cUnit, kOpBlx, rLR);
966 oatClobberCalleeSave(cUnit);
967 return;
968 }
969 }
970 }
971
buzbee561227c2011-09-02 15:28:19 -0700972 if (range) {
973 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700974 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700975 } else {
976 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700977 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700978 }
buzbee67bf8852011-08-17 17:51:35 -0700979 // Finish up any of the call sequence not interleaved in arg loading
980 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700981 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700982 }
buzbeece302932011-10-04 14:32:18 -0700983 if (DISPLAY_MISSING_TARGETS) {
984 genShowTarget(cUnit);
985 }
buzbeeec5adf32011-09-11 15:25:43 -0700986 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -0700987 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700988}
989
buzbee4a3164f2011-09-03 11:25:10 -0700990/*
991 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
992 * which will locate the target and continue on via a tail call.
993 */
buzbeeed3e9302011-09-23 17:34:19 -0700994STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -0700995{
996 DecodedInstruction* dInsn = &mir->dalvikInsn;
997 int callState = 0;
998 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -0700999 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001000
1001 // Explicit register usage
1002 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001003 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -07001004 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001005 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
1006 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001007 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -07001008 false);
buzbee67bf8852011-08-17 17:51:35 -07001009 else
1010 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -07001011 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -07001012 // Finish up any of the call sequence not interleaved in arg loading
1013 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001014 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001015 }
buzbeece302932011-10-04 14:32:18 -07001016 if (DISPLAY_MISSING_TARGETS) {
1017 genShowTarget(cUnit);
1018 }
buzbeeec5adf32011-09-11 15:25:43 -07001019 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001020 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001021}
1022
buzbeeed3e9302011-09-23 17:34:19 -07001023STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001024{
1025 DecodedInstruction* dInsn = &mir->dalvikInsn;
1026 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001027 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001028 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1029 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -07001030 NextCallInsn nextCallInsn;
1031 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001032 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001033
1034 // Explicit register usage
1035 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001036 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -07001037 fastPath = false;
1038 } else {
1039 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
1040 if (superClass == NULL) {
1041 fastPath = false;
1042 } else {
1043 int32_t target_idx = baseMethod->GetMethodIndex();
1044 if (superClass->GetVTable()->GetLength() <= target_idx) {
1045 fastPath = false;
1046 } else {
1047 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1048 }
1049 }
1050 }
1051 if (fastPath) {
1052 nextCallInsn = nextSuperCallInsn;
1053 rollback = NULL;
1054 } else {
1055 nextCallInsn = nextSuperCallInsnSP;
1056 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1057 rollback->defMask = -1;
1058 }
buzbee67bf8852011-08-17 17:51:35 -07001059 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001060 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001061 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001062 else
buzbeec0ecd652011-09-25 18:11:54 -07001063 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001064 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001065 // Finish up any of the call sequence not interleaved in arg loading
1066 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001067 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001068 }
buzbeece302932011-10-04 14:32:18 -07001069 if (DISPLAY_MISSING_TARGETS) {
1070 genShowTarget(cUnit);
1071 }
buzbeeec5adf32011-09-11 15:25:43 -07001072 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001073 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001074}
1075
buzbeeed3e9302011-09-23 17:34:19 -07001076STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001077{
1078 DecodedInstruction* dInsn = &mir->dalvikInsn;
1079 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001080 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001081 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1082 Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -07001083 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001084 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee7b1b86d2011-08-26 18:59:10 -07001085
buzbee109bd6a2011-09-06 13:58:41 -07001086 // Explicit register usage
1087 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001088 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001089 // Slow path
1090 nextCallInsn = nextVCallInsnSP;
1091 // If we need a slow-path callout, we'll restart here
1092 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1093 rollback->defMask = -1;
1094 } else {
1095 // Fast path
1096 nextCallInsn = nextVCallInsn;
1097 rollback = NULL;
1098 }
buzbee67bf8852011-08-17 17:51:35 -07001099 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001100 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001101 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001102 else
buzbeec0ecd652011-09-25 18:11:54 -07001103 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001104 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001105 // Finish up any of the call sequence not interleaved in arg loading
1106 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001107 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001108 }
buzbeece302932011-10-04 14:32:18 -07001109 if (DISPLAY_MISSING_TARGETS) {
1110 genShowTarget(cUnit);
1111 }
buzbeeec5adf32011-09-11 15:25:43 -07001112 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001113 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001114}
1115
buzbeeed3e9302011-09-23 17:34:19 -07001116STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001117 BasicBlock* bb, ArmLIR* labelList)
1118{
1119 bool res = false; // Assume success
1120 RegLocation rlSrc[3];
1121 RegLocation rlDest = badLoc;
1122 RegLocation rlResult = badLoc;
1123 Opcode opcode = mir->dalvikInsn.opcode;
1124
1125 /* Prep Src and Dest locations */
1126 int nextSreg = 0;
1127 int nextLoc = 0;
1128 int attrs = oatDataFlowAttributes[opcode];
1129 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1130 if (attrs & DF_UA) {
1131 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1132 nextSreg++;
1133 } else if (attrs & DF_UA_WIDE) {
1134 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1135 nextSreg + 1);
1136 nextSreg+= 2;
1137 }
1138 if (attrs & DF_UB) {
1139 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1140 nextSreg++;
1141 } else if (attrs & DF_UB_WIDE) {
1142 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1143 nextSreg + 1);
1144 nextSreg+= 2;
1145 }
1146 if (attrs & DF_UC) {
1147 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1148 } else if (attrs & DF_UC_WIDE) {
1149 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1150 nextSreg + 1);
1151 }
1152 if (attrs & DF_DA) {
1153 rlDest = oatGetDest(cUnit, mir, 0);
1154 } else if (attrs & DF_DA_WIDE) {
1155 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1156 }
1157
1158 switch(opcode) {
1159 case OP_NOP:
1160 break;
1161
1162 case OP_MOVE_EXCEPTION:
1163 int exOffset;
1164 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001165 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001166 resetReg = oatAllocTemp(cUnit);
1167 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1168 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1169 loadConstant(cUnit, resetReg, 0);
1170 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1171 storeValue(cUnit, rlDest, rlResult);
1172 break;
1173
1174 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -07001175 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001176 break;
1177
1178 case OP_RETURN:
1179 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -07001180 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001181 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001182 break;
1183
1184 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -07001185 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001186 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001187 break;
1188
1189 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001190 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001191 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001192 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001193 break;
1194
1195 case OP_MOVE_RESULT:
1196 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001197 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001198 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001199 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001200 break;
1201
1202 case OP_MOVE:
1203 case OP_MOVE_OBJECT:
1204 case OP_MOVE_16:
1205 case OP_MOVE_OBJECT_16:
1206 case OP_MOVE_FROM16:
1207 case OP_MOVE_OBJECT_FROM16:
1208 storeValue(cUnit, rlDest, rlSrc[0]);
1209 break;
1210
1211 case OP_MOVE_WIDE:
1212 case OP_MOVE_WIDE_16:
1213 case OP_MOVE_WIDE_FROM16:
1214 storeValueWide(cUnit, rlDest, rlSrc[0]);
1215 break;
1216
1217 case OP_CONST:
1218 case OP_CONST_4:
1219 case OP_CONST_16:
1220 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1221 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1222 storeValue(cUnit, rlDest, rlResult);
1223 break;
1224
1225 case OP_CONST_HIGH16:
1226 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1227 loadConstantNoClobber(cUnit, rlResult.lowReg,
1228 mir->dalvikInsn.vB << 16);
1229 storeValue(cUnit, rlDest, rlResult);
1230 break;
1231
1232 case OP_CONST_WIDE_16:
1233 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001234 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1235 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1236 mir->dalvikInsn.vB,
1237 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001238 storeValueWide(cUnit, rlDest, rlResult);
1239 break;
1240
1241 case OP_CONST_WIDE:
1242 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1243 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001244 mir->dalvikInsn.vB_wide & 0xffffffff,
1245 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001246 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001247 break;
1248
1249 case OP_CONST_WIDE_HIGH16:
1250 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1251 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1252 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001253 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001254 break;
1255
1256 case OP_MONITOR_ENTER:
1257 genMonitorEnter(cUnit, mir, rlSrc[0]);
1258 break;
1259
1260 case OP_MONITOR_EXIT:
1261 genMonitorExit(cUnit, mir, rlSrc[0]);
1262 break;
1263
1264 case OP_CHECK_CAST:
1265 genCheckCast(cUnit, mir, rlSrc[0]);
1266 break;
1267
1268 case OP_INSTANCE_OF:
1269 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1270 break;
1271
1272 case OP_NEW_INSTANCE:
1273 genNewInstance(cUnit, mir, rlDest);
1274 break;
1275
1276 case OP_THROW:
1277 genThrow(cUnit, mir, rlSrc[0]);
1278 break;
1279
buzbee5ade1d22011-09-09 14:44:52 -07001280 case OP_THROW_VERIFICATION_ERROR:
1281 loadWordDisp(cUnit, rSELF,
1282 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1283 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1284 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001285 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001286 break;
1287
buzbee67bf8852011-08-17 17:51:35 -07001288 case OP_ARRAY_LENGTH:
1289 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001290 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001291 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001292 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001293 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1294 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1295 rlResult.lowReg);
1296 storeValue(cUnit, rlDest, rlResult);
1297 break;
1298
1299 case OP_CONST_STRING:
1300 case OP_CONST_STRING_JUMBO:
1301 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1302 break;
1303
1304 case OP_CONST_CLASS:
1305 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1306 break;
1307
1308 case OP_FILL_ARRAY_DATA:
1309 genFillArrayData(cUnit, mir, rlSrc[0]);
1310 break;
1311
1312 case OP_FILLED_NEW_ARRAY:
1313 genFilledNewArray(cUnit, mir, false /* not range */);
1314 break;
1315
1316 case OP_FILLED_NEW_ARRAY_RANGE:
1317 genFilledNewArray(cUnit, mir, true /* range */);
1318 break;
1319
1320 case OP_NEW_ARRAY:
1321 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1322 break;
1323
1324 case OP_GOTO:
1325 case OP_GOTO_16:
1326 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001327 if (bb->taken->startOffset <= mir->offset) {
1328 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001329 }
1330 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1331 break;
1332
1333 case OP_PACKED_SWITCH:
1334 genPackedSwitch(cUnit, mir, rlSrc[0]);
1335 break;
1336
1337 case OP_SPARSE_SWITCH:
1338 genSparseSwitch(cUnit, mir, rlSrc[0]);
1339 break;
1340
1341 case OP_CMPL_FLOAT:
1342 case OP_CMPG_FLOAT:
1343 case OP_CMPL_DOUBLE:
1344 case OP_CMPG_DOUBLE:
1345 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1346 break;
1347
1348 case OP_CMP_LONG:
1349 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1350 break;
1351
1352 case OP_IF_EQ:
1353 case OP_IF_NE:
1354 case OP_IF_LT:
1355 case OP_IF_GE:
1356 case OP_IF_GT:
1357 case OP_IF_LE: {
1358 bool backwardBranch;
1359 ArmConditionCode cond;
1360 backwardBranch = (bb->taken->startOffset <= mir->offset);
1361 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001362 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001363 }
1364 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1365 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1366 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1367 switch(opcode) {
1368 case OP_IF_EQ:
1369 cond = kArmCondEq;
1370 break;
1371 case OP_IF_NE:
1372 cond = kArmCondNe;
1373 break;
1374 case OP_IF_LT:
1375 cond = kArmCondLt;
1376 break;
1377 case OP_IF_GE:
1378 cond = kArmCondGe;
1379 break;
1380 case OP_IF_GT:
1381 cond = kArmCondGt;
1382 break;
1383 case OP_IF_LE:
1384 cond = kArmCondLe;
1385 break;
1386 default:
1387 cond = (ArmConditionCode)0;
1388 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1389 }
1390 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1391 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1392 break;
1393 }
1394
1395 case OP_IF_EQZ:
1396 case OP_IF_NEZ:
1397 case OP_IF_LTZ:
1398 case OP_IF_GEZ:
1399 case OP_IF_GTZ:
1400 case OP_IF_LEZ: {
1401 bool backwardBranch;
1402 ArmConditionCode cond;
1403 backwardBranch = (bb->taken->startOffset <= mir->offset);
1404 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001405 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001406 }
1407 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1408 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1409 switch(opcode) {
1410 case OP_IF_EQZ:
1411 cond = kArmCondEq;
1412 break;
1413 case OP_IF_NEZ:
1414 cond = kArmCondNe;
1415 break;
1416 case OP_IF_LTZ:
1417 cond = kArmCondLt;
1418 break;
1419 case OP_IF_GEZ:
1420 cond = kArmCondGe;
1421 break;
1422 case OP_IF_GTZ:
1423 cond = kArmCondGt;
1424 break;
1425 case OP_IF_LEZ:
1426 cond = kArmCondLe;
1427 break;
1428 default:
1429 cond = (ArmConditionCode)0;
1430 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1431 }
1432 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1433 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1434 break;
1435 }
1436
1437 case OP_AGET_WIDE:
1438 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1439 break;
1440 case OP_AGET:
1441 case OP_AGET_OBJECT:
1442 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1443 break;
1444 case OP_AGET_BOOLEAN:
1445 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1446 rlDest, 0);
1447 break;
1448 case OP_AGET_BYTE:
1449 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1450 break;
1451 case OP_AGET_CHAR:
1452 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1453 rlDest, 1);
1454 break;
1455 case OP_AGET_SHORT:
1456 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1457 break;
1458 case OP_APUT_WIDE:
1459 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1460 break;
1461 case OP_APUT:
1462 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1463 break;
1464 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001465 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001466 break;
1467 case OP_APUT_SHORT:
1468 case OP_APUT_CHAR:
1469 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1470 rlSrc[0], 1);
1471 break;
1472 case OP_APUT_BYTE:
1473 case OP_APUT_BOOLEAN:
1474 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1475 rlSrc[0], 0);
1476 break;
1477
1478 case OP_IGET_WIDE:
1479 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001480 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001481 break;
1482
1483 case OP_IGET:
1484 case OP_IGET_VOLATILE:
1485 case OP_IGET_OBJECT:
1486 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001487 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001488 break;
1489
1490 case OP_IGET_BOOLEAN:
1491 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001492 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001493 break;
1494
1495 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001496 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001497 break;
1498
1499 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001500 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001501 break;
1502
1503 case OP_IPUT_WIDE:
1504 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001505 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001506 break;
1507
1508 case OP_IPUT_OBJECT:
1509 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001510 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001511 break;
1512
1513 case OP_IPUT:
1514 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001515 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001516 break;
1517
1518 case OP_IPUT_BOOLEAN:
1519 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001520 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001521 break;
1522
1523 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001524 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001525 break;
1526
1527 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001528 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001529 break;
1530
1531 case OP_SGET:
1532 case OP_SGET_OBJECT:
1533 case OP_SGET_BOOLEAN:
1534 case OP_SGET_BYTE:
1535 case OP_SGET_CHAR:
1536 case OP_SGET_SHORT:
1537 genSget(cUnit, mir, rlResult, rlDest);
1538 break;
1539
1540 case OP_SGET_WIDE:
1541 genSgetWide(cUnit, mir, rlResult, rlDest);
1542 break;
1543
1544 case OP_SPUT:
1545 case OP_SPUT_OBJECT:
1546 case OP_SPUT_BOOLEAN:
1547 case OP_SPUT_BYTE:
1548 case OP_SPUT_CHAR:
1549 case OP_SPUT_SHORT:
1550 genSput(cUnit, mir, rlSrc[0]);
1551 break;
1552
1553 case OP_SPUT_WIDE:
1554 genSputWide(cUnit, mir, rlSrc[0]);
1555 break;
1556
1557 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001558 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1559 true /*range*/);
1560 break;
buzbee67bf8852011-08-17 17:51:35 -07001561 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001562 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1563 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001564 break;
1565
1566 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001567 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1568 false /*range*/);
1569 break;
buzbee67bf8852011-08-17 17:51:35 -07001570 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001571 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1572 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001573 break;
1574
1575 case OP_INVOKE_VIRTUAL:
1576 case OP_INVOKE_VIRTUAL_RANGE:
1577 genInvokeVirtual(cUnit, mir);
1578 break;
1579
1580 case OP_INVOKE_SUPER:
1581 case OP_INVOKE_SUPER_RANGE:
1582 genInvokeSuper(cUnit, mir);
1583 break;
1584
1585 case OP_INVOKE_INTERFACE:
1586 case OP_INVOKE_INTERFACE_RANGE:
1587 genInvokeInterface(cUnit, mir);
1588 break;
1589
1590 case OP_NEG_INT:
1591 case OP_NOT_INT:
1592 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1593 break;
1594
1595 case OP_NEG_LONG:
1596 case OP_NOT_LONG:
1597 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1598 break;
1599
1600 case OP_NEG_FLOAT:
1601 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1602 break;
1603
1604 case OP_NEG_DOUBLE:
1605 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1606 break;
1607
1608 case OP_INT_TO_LONG:
1609 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1610 if (rlSrc[0].location == kLocPhysReg) {
1611 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1612 } else {
1613 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1614 }
1615 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1616 rlResult.lowReg, 31);
1617 storeValueWide(cUnit, rlDest, rlResult);
1618 break;
1619
1620 case OP_LONG_TO_INT:
1621 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1622 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1623 storeValue(cUnit, rlDest, rlSrc[0]);
1624 break;
1625
1626 case OP_INT_TO_BYTE:
1627 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1628 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1629 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1630 storeValue(cUnit, rlDest, rlResult);
1631 break;
1632
1633 case OP_INT_TO_SHORT:
1634 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1635 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1636 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1637 storeValue(cUnit, rlDest, rlResult);
1638 break;
1639
1640 case OP_INT_TO_CHAR:
1641 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1642 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1643 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1644 storeValue(cUnit, rlDest, rlResult);
1645 break;
1646
1647 case OP_INT_TO_FLOAT:
1648 case OP_INT_TO_DOUBLE:
1649 case OP_LONG_TO_FLOAT:
1650 case OP_LONG_TO_DOUBLE:
1651 case OP_FLOAT_TO_INT:
1652 case OP_FLOAT_TO_LONG:
1653 case OP_FLOAT_TO_DOUBLE:
1654 case OP_DOUBLE_TO_INT:
1655 case OP_DOUBLE_TO_LONG:
1656 case OP_DOUBLE_TO_FLOAT:
1657 genConversion(cUnit, mir);
1658 break;
1659
1660 case OP_ADD_INT:
1661 case OP_SUB_INT:
1662 case OP_MUL_INT:
1663 case OP_DIV_INT:
1664 case OP_REM_INT:
1665 case OP_AND_INT:
1666 case OP_OR_INT:
1667 case OP_XOR_INT:
1668 case OP_SHL_INT:
1669 case OP_SHR_INT:
1670 case OP_USHR_INT:
1671 case OP_ADD_INT_2ADDR:
1672 case OP_SUB_INT_2ADDR:
1673 case OP_MUL_INT_2ADDR:
1674 case OP_DIV_INT_2ADDR:
1675 case OP_REM_INT_2ADDR:
1676 case OP_AND_INT_2ADDR:
1677 case OP_OR_INT_2ADDR:
1678 case OP_XOR_INT_2ADDR:
1679 case OP_SHL_INT_2ADDR:
1680 case OP_SHR_INT_2ADDR:
1681 case OP_USHR_INT_2ADDR:
1682 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1683 break;
1684
1685 case OP_ADD_LONG:
1686 case OP_SUB_LONG:
1687 case OP_MUL_LONG:
1688 case OP_DIV_LONG:
1689 case OP_REM_LONG:
1690 case OP_AND_LONG:
1691 case OP_OR_LONG:
1692 case OP_XOR_LONG:
1693 case OP_ADD_LONG_2ADDR:
1694 case OP_SUB_LONG_2ADDR:
1695 case OP_MUL_LONG_2ADDR:
1696 case OP_DIV_LONG_2ADDR:
1697 case OP_REM_LONG_2ADDR:
1698 case OP_AND_LONG_2ADDR:
1699 case OP_OR_LONG_2ADDR:
1700 case OP_XOR_LONG_2ADDR:
1701 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1702 break;
1703
buzbee67bf8852011-08-17 17:51:35 -07001704 case OP_SHL_LONG:
1705 case OP_SHR_LONG:
1706 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001707 case OP_SHL_LONG_2ADDR:
1708 case OP_SHR_LONG_2ADDR:
1709 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001710 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1711 break;
1712
1713 case OP_ADD_FLOAT:
1714 case OP_SUB_FLOAT:
1715 case OP_MUL_FLOAT:
1716 case OP_DIV_FLOAT:
1717 case OP_REM_FLOAT:
1718 case OP_ADD_FLOAT_2ADDR:
1719 case OP_SUB_FLOAT_2ADDR:
1720 case OP_MUL_FLOAT_2ADDR:
1721 case OP_DIV_FLOAT_2ADDR:
1722 case OP_REM_FLOAT_2ADDR:
1723 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1724 break;
1725
1726 case OP_ADD_DOUBLE:
1727 case OP_SUB_DOUBLE:
1728 case OP_MUL_DOUBLE:
1729 case OP_DIV_DOUBLE:
1730 case OP_REM_DOUBLE:
1731 case OP_ADD_DOUBLE_2ADDR:
1732 case OP_SUB_DOUBLE_2ADDR:
1733 case OP_MUL_DOUBLE_2ADDR:
1734 case OP_DIV_DOUBLE_2ADDR:
1735 case OP_REM_DOUBLE_2ADDR:
1736 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1737 break;
1738
1739 case OP_RSUB_INT:
1740 case OP_ADD_INT_LIT16:
1741 case OP_MUL_INT_LIT16:
1742 case OP_DIV_INT_LIT16:
1743 case OP_REM_INT_LIT16:
1744 case OP_AND_INT_LIT16:
1745 case OP_OR_INT_LIT16:
1746 case OP_XOR_INT_LIT16:
1747 case OP_ADD_INT_LIT8:
1748 case OP_RSUB_INT_LIT8:
1749 case OP_MUL_INT_LIT8:
1750 case OP_DIV_INT_LIT8:
1751 case OP_REM_INT_LIT8:
1752 case OP_AND_INT_LIT8:
1753 case OP_OR_INT_LIT8:
1754 case OP_XOR_INT_LIT8:
1755 case OP_SHL_INT_LIT8:
1756 case OP_SHR_INT_LIT8:
1757 case OP_USHR_INT_LIT8:
1758 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1759 break;
1760
1761 default:
1762 res = true;
1763 }
1764 return res;
1765}
1766
buzbeeed3e9302011-09-23 17:34:19 -07001767STATIC const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001768 "kMirOpPhi",
1769 "kMirOpNullNRangeUpCheck",
1770 "kMirOpNullNRangeDownCheck",
1771 "kMirOpLowerBound",
1772 "kMirOpPunt",
1773 "kMirOpCheckInlinePrediction",
1774};
1775
1776/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001777STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001778{
1779 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1780 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1781 strcpy(msg, extendedMIROpNames[opOffset]);
1782 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1783
1784 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1785 case kMirOpPhi: {
1786 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1787 op->flags.isNop = true;
1788 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1789 break;
1790 }
1791 default:
1792 break;
1793 }
1794}
1795
buzbee67bc2362011-10-11 18:08:40 -07001796/*
1797 * If there are any ins passed in registers that have not been promoted
1798 * to a callee-save register, flush them to the frame. Perform intial
1799 * assignment of promoted arguments.
1800 */
buzbeeed3e9302011-09-23 17:34:19 -07001801STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001802{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001803 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001804 return;
buzbee67bc2362011-10-11 18:08:40 -07001805 int firstArgReg = r1;
1806 int lastArgReg = r3;
1807 int startVReg = cUnit->method->NumRegisters() -
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001808 cUnit->method->NumIns();
buzbee8febc582011-10-25 12:39:20 -07001809 /*
1810 * Arguments passed in registers should be flushed
1811 * to their backing locations in the frame for now.
1812 * Also, we need to do initial assignment for promoted
1813 * arguments. NOTE: an older version of dx had an issue
1814 * in which it would reuse static method argument registers.
1815 * This could result in the same Dalvik virtual register
1816 * being promoted to both core and fp regs. In those
1817 * cases, copy argument to both. This will be uncommon
1818 * enough that it isn't worth attempting to optimize.
1819 */
buzbee67bc2362011-10-11 18:08:40 -07001820 for (int i = 0; i < cUnit->method->NumIns(); i++) {
1821 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001822 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001823 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001824 if (vMap.coreLocation == kLocPhysReg) {
1825 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001826 }
1827 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001828 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1829 }
1830 // Also put a copy in memory in case we're partially promoted
1831 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1832 firstArgReg + i, kWord);
1833 } else {
buzbee8febc582011-10-25 12:39:20 -07001834 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001835 if (vMap.coreLocation == kLocPhysReg) {
1836 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1837 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001838 }
1839 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001840 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1841 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001842 }
1843 }
buzbee67bf8852011-08-17 17:51:35 -07001844 }
1845}
1846
1847/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001848STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001849{
1850 MIR* mir;
1851 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1852 int blockId = bb->id;
1853
1854 cUnit->curBlock = bb;
1855 labelList[blockId].operands[0] = bb->startOffset;
1856
1857 /* Insert the block label */
1858 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1859 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1860
buzbee6181f792011-09-29 11:14:04 -07001861 /* Reset local optimization data on block boundaries */
1862 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001863 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001864 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001865
1866 ArmLIR* headLIR = NULL;
1867
buzbeebbaf8942011-10-02 13:08:29 -07001868 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001869 if (bb->blockType == kEntryBlock) {
1870 /*
1871 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1872 * mechanism know so it doesn't try to use any of them when
1873 * expanding the frame or flushing. This leaves the utility
1874 * code with a single temp: r12. This should be enough.
1875 */
1876 oatLockTemp(cUnit, r0);
1877 oatLockTemp(cUnit, r1);
1878 oatLockTemp(cUnit, r2);
1879 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001880
1881 /*
1882 * We can safely skip the stack overflow check if we're
1883 * a leaf *and* our frame size < fudge factor.
1884 */
1885 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1886 ((size_t)cUnit->frameSize <
1887 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001888 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001889 if (!skipOverflowCheck) {
1890 /* Load stack limit */
1891 loadWordDisp(cUnit, rSELF,
1892 art::Thread::StackEndOffset().Int32Value(), r12);
1893 }
buzbee67bf8852011-08-17 17:51:35 -07001894 /* Spill core callee saves */
1895 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1896 /* Need to spill any FP regs? */
1897 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001898 /*
1899 * NOTE: fp spills are a little different from core spills in that
1900 * they are pushed as a contiguous block. When promoting from
1901 * the fp set, we must allocate all singles from s16..highest-promoted
1902 */
buzbee67bf8852011-08-17 17:51:35 -07001903 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1904 }
buzbeecefd1872011-09-09 09:59:52 -07001905 if (!skipOverflowCheck) {
1906 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001907 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001908 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1909 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001910 genRegCopy(cUnit, rSP, rLR); // Establish stack
1911 } else {
1912 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001913 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001914 }
buzbee67bf8852011-08-17 17:51:35 -07001915 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1916 flushIns(cUnit);
1917 oatFreeTemp(cUnit, r0);
1918 oatFreeTemp(cUnit, r1);
1919 oatFreeTemp(cUnit, r2);
1920 oatFreeTemp(cUnit, r3);
1921 } else if (bb->blockType == kExitBlock) {
1922 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07001923 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07001924 /* Need to restore any FP callee saves? */
1925 if (cUnit->numFPSpills) {
1926 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1927 }
1928 if (cUnit->coreSpillMask & (1 << rLR)) {
1929 /* Unspill rLR to rPC */
1930 cUnit->coreSpillMask &= ~(1 << rLR);
1931 cUnit->coreSpillMask |= (1 << rPC);
1932 }
1933 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1934 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1935 /* We didn't pop to rPC, so must do a bv rLR */
1936 newLIR1(cUnit, kThumbBx, rLR);
1937 }
1938 }
1939
1940 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1941
1942 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07001943 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1944 oatClobberAllRegs(cUnit);
1945 }
buzbee67bf8852011-08-17 17:51:35 -07001946
1947 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1948 oatResetDefTracking(cUnit);
1949 }
1950
1951 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1952 handleExtendedMethodMIR(cUnit, mir);
1953 continue;
1954 }
1955
1956 cUnit->currentDalvikOffset = mir->offset;
1957
1958 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1959 InstructionFormat dalvikFormat =
1960 dexGetFormatFromOpcode(dalvikOpcode);
1961
1962 ArmLIR* boundaryLIR;
1963
1964 /* Mark the beginning of a Dalvik instruction for line tracking */
1965 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1966 (int) oatGetDalvikDisassembly(
1967 &mir->dalvikInsn, ""));
1968 /* Remember the first LIR for this block */
1969 if (headLIR == NULL) {
1970 headLIR = boundaryLIR;
1971 /* Set the first boundaryLIR as a scheduling barrier */
1972 headLIR->defMask = ENCODE_ALL;
1973 }
1974
1975 /* Don't generate the SSA annotation unless verbose mode is on */
1976 if (cUnit->printMe && mir->ssaRep) {
1977 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1978 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1979 }
1980
1981 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1982
1983 if (notHandled) {
1984 char buf[100];
1985 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1986 mir->offset,
1987 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1988 dalvikFormat);
1989 LOG(FATAL) << buf;
1990 }
1991 }
1992
1993 if (headLIR) {
1994 /*
1995 * Eliminate redundant loads/stores and delay stores into later
1996 * slots
1997 */
1998 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1999 cUnit->lastLIRInsn);
2000
2001 /*
2002 * Generate an unconditional branch to the fallthrough block.
2003 */
2004 if (bb->fallThrough) {
2005 genUnconditionalBranch(cUnit,
2006 &labelList[bb->fallThrough->id]);
2007 }
2008 }
2009 return false;
2010}
2011
2012/*
2013 * Nop any unconditional branches that go to the next instruction.
2014 * Note: new redundant branches may be inserted later, and we'll
2015 * use a check in final instruction assembly to nop those out.
2016 */
2017void removeRedundantBranches(CompilationUnit* cUnit)
2018{
2019 ArmLIR* thisLIR;
2020
2021 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2022 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2023 thisLIR = NEXT_LIR(thisLIR)) {
2024
2025 /* Branch to the next instruction */
2026 if ((thisLIR->opcode == kThumbBUncond) ||
2027 (thisLIR->opcode == kThumb2BUncond)) {
2028 ArmLIR* nextLIR = thisLIR;
2029
2030 while (true) {
2031 nextLIR = NEXT_LIR(nextLIR);
2032
2033 /*
2034 * Is the branch target the next instruction?
2035 */
2036 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2037 thisLIR->flags.isNop = true;
2038 break;
2039 }
2040
2041 /*
2042 * Found real useful stuff between the branch and the target.
2043 * Need to explicitly check the lastLIRInsn here because it
2044 * might be the last real instruction.
2045 */
2046 if (!isPseudoOpcode(nextLIR->opcode) ||
2047 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2048 break;
2049 }
2050 }
2051 }
2052}
2053
buzbeeed3e9302011-09-23 17:34:19 -07002054STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002055{
2056 ArmLIR** suspendLabel =
2057 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2058 int numElems = cUnit->suspendLaunchpads.numUsed;
2059
2060 for (int i = 0; i < numElems; i++) {
2061 /* TUNING: move suspend count load into helper */
2062 ArmLIR* lab = suspendLabel[i];
2063 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2064 cUnit->currentDalvikOffset = lab->operands[1];
2065 oatAppendLIR(cUnit, (LIR *)lab);
2066 loadWordDisp(cUnit, rSELF,
2067 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2068 loadWordDisp(cUnit, rSELF,
2069 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2070 opReg(cUnit, kOpBlx, rLR);
2071 genUnconditionalBranch(cUnit, resumeLab);
2072 }
2073}
2074
buzbeeed3e9302011-09-23 17:34:19 -07002075STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002076{
2077 ArmLIR** throwLabel =
2078 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2079 int numElems = cUnit->throwLaunchpads.numUsed;
2080 int i;
2081
2082 for (i = 0; i < numElems; i++) {
2083 ArmLIR* lab = throwLabel[i];
2084 cUnit->currentDalvikOffset = lab->operands[1];
2085 oatAppendLIR(cUnit, (LIR *)lab);
2086 int funcOffset = 0;
2087 int v1 = lab->operands[2];
2088 int v2 = lab->operands[3];
2089 switch(lab->operands[0]) {
2090 case kArmThrowNullPointer:
2091 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2092 break;
2093 case kArmThrowArrayBounds:
2094 if (v2 != r0) {
2095 genRegCopy(cUnit, r0, v1);
2096 genRegCopy(cUnit, r1, v2);
2097 } else {
2098 if (v1 == r1) {
2099 genRegCopy(cUnit, r12, v1);
2100 genRegCopy(cUnit, r1, v2);
2101 genRegCopy(cUnit, r0, r12);
2102 } else {
2103 genRegCopy(cUnit, r1, v2);
2104 genRegCopy(cUnit, r0, v1);
2105 }
2106 }
2107 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2108 break;
2109 case kArmThrowDivZero:
2110 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2111 break;
2112 case kArmThrowVerificationError:
2113 loadConstant(cUnit, r0, v1);
2114 loadConstant(cUnit, r1, v2);
2115 funcOffset =
2116 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2117 break;
2118 case kArmThrowNegArraySize:
2119 genRegCopy(cUnit, r0, v1);
2120 funcOffset =
2121 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2122 break;
buzbee5ade1d22011-09-09 14:44:52 -07002123 case kArmThrowNoSuchMethod:
2124 genRegCopy(cUnit, r0, v1);
2125 funcOffset =
2126 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2127 break;
buzbeeec5adf32011-09-11 15:25:43 -07002128 case kArmThrowStackOverflow:
2129 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002130 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002131 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002132 opRegImm(cUnit, kOpAdd, rSP,
2133 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002134 break;
buzbee5ade1d22011-09-09 14:44:52 -07002135 default:
2136 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2137 }
2138 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002139 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002140 }
2141}
2142
buzbee67bf8852011-08-17 17:51:35 -07002143void oatMethodMIR2LIR(CompilationUnit* cUnit)
2144{
2145 /* Used to hold the labels of each block */
2146 cUnit->blockLabelList =
2147 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2148
2149 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2150 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002151 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002152
2153 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002154
2155 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002156}
2157
2158/* Common initialization routine for an architecture family */
2159bool oatArchInit()
2160{
2161 int i;
2162
2163 for (i = 0; i < kArmLast; i++) {
2164 if (EncodingMap[i].opcode != i) {
2165 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2166 " is wrong: expecting " << i << ", seeing " <<
2167 (int)EncodingMap[i].opcode;
2168 }
2169 }
2170
2171 return oatArchVariantInit();
2172}
2173
2174/* Needed by the Assembler */
2175void oatSetupResourceMasks(ArmLIR* lir)
2176{
2177 setupResourceMasks(lir);
2178}
2179
2180/* Needed by the ld/st optmizatons */
2181ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2182{
2183 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2184}
2185
2186/* Needed by the register allocator */
2187ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2188{
2189 return genRegCopy(cUnit, rDest, rSrc);
2190}
2191
2192/* Needed by the register allocator */
2193void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2194 int srcLo, int srcHi)
2195{
2196 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2197}
2198
2199void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2200 int displacement, int rSrc, OpSize size)
2201{
2202 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2203}
2204
2205void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2206 int displacement, int rSrcLo, int rSrcHi)
2207{
2208 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2209}