blob: a32446ac8a284baed43b7bcc8ae530ed54d9c749 [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 */
Ian Rogers28ad40d2011-10-27 15:19:26 -070049 uint32_t type_idx = mir->dalvikInsn.vC;
50 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
51 loadWordDisp(cUnit, rSELF,
52 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
53 } else {
54 UNIMPLEMENTED(WARNING) << "Need to check access of '"
55 << PrettyMethod(cUnit->method)
56 << "' to unresolved type " << type_idx;
57 loadWordDisp(cUnit, rSELF,
58 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
59 }
buzbeedfd3d702011-08-28 12:56:51 -070060 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -070061 loadConstant(cUnit, r0, type_idx); // arg0 <- type_id
buzbeedfd3d702011-08-28 12:56:51 -070062 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070063 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070064 RegLocation rlResult = oatGetReturn(cUnit);
65 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070066}
67
68/*
69 * Similar to genNewArray, but with post-allocation initialization.
70 * Verifier guarantees we're dealing with an array class. Current
71 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
72 * Current code also throws internal unimp if not 'L', '[' or 'I'.
73 */
buzbeeed3e9302011-09-23 17:34:19 -070074STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070075{
76 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070077 int elems = dInsn->vA;
78 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070079 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070080 loadWordDisp(cUnit, rSELF,
Elliott Hughesb408de72011-10-04 14:35:05 -070081 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
Ian Rogers28ad40d2011-10-27 15:19:26 -070082 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, typeId)) {
83 UNIMPLEMENTED(WARNING) << "Need to check access of '" << PrettyMethod(cUnit->method)
84 << "' to unresolved type " << typeId;
85 }
buzbeedfd3d702011-08-28 12:56:51 -070086 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
87 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
88 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070089 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070090 /*
buzbeedfd3d702011-08-28 12:56:51 -070091 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
92 * return region. Because AllocFromCode placed the new array
93 * in r0, we'll just lock it into place. When debugger support is
94 * added, it may be necessary to additionally copy all return
95 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070096 */
buzbee67bf8852011-08-17 17:51:35 -070097 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070098
buzbee67bf8852011-08-17 17:51:35 -070099 // Having a range of 0 is legal
100 if (isRange && (dInsn->vA > 0)) {
101 /*
102 * Bit of ugliness here. We're going generate a mem copy loop
103 * on the register range, but it is possible that some regs
104 * in the range have been promoted. This is unlikely, but
105 * before generating the copy, we'll just force a flush
106 * of any regs in the source range that have been promoted to
107 * home location.
108 */
109 for (unsigned int i = 0; i < dInsn->vA; i++) {
110 RegLocation loc = oatUpdateLoc(cUnit,
111 oatGetSrc(cUnit, mir, i));
112 if (loc.location == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -0700113 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
114 loc.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700115 }
116 }
117 /*
118 * TUNING note: generated code here could be much improved, but
119 * this is an uncommon operation and isn't especially performance
120 * critical.
121 */
122 int rSrc = oatAllocTemp(cUnit);
123 int rDst = oatAllocTemp(cUnit);
124 int rIdx = oatAllocTemp(cUnit);
125 int rVal = rLR; // Using a lot of temps, rLR is known free here
126 // Set up source pointer
127 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
buzbee67bc2362011-10-11 18:08:40 -0700128 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
129 oatSRegOffset(cUnit, rlFirst.sRegLow));
buzbee67bf8852011-08-17 17:51:35 -0700130 // Set up the target pointer
131 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700132 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700133 // Set up the loop counter (known to be > 0)
buzbee31813452011-10-16 14:33:08 -0700134 loadConstant(cUnit, rIdx, dInsn->vA - 1);
buzbee67bf8852011-08-17 17:51:35 -0700135 // Generate the copy loop. Going backwards for convenience
136 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
137 target->defMask = ENCODE_ALL;
138 // Copy next element
139 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
140 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
141 // Use setflags encoding here
142 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee31813452011-10-16 14:33:08 -0700143 ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
buzbee67bf8852011-08-17 17:51:35 -0700144 branch->generic.target = (LIR*)target;
145 } else if (!isRange) {
146 // TUNING: interleave
147 for (unsigned int i = 0; i < dInsn->vA; i++) {
148 RegLocation rlArg = loadValue(cUnit,
149 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700150 storeBaseDisp(cUnit, r0,
151 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700152 i * 4, rlArg.lowReg, kWord);
153 // If the loadValue caused a temp to be allocated, free it
154 if (oatIsTemp(cUnit, rlArg.lowReg)) {
155 oatFreeTemp(cUnit, rlArg.lowReg);
156 }
157 }
158 }
159}
160
Brian Carlstrom845490b2011-09-19 15:56:53 -0700161Field* FindFieldWithResolvedStaticStorage(const Method* method,
162 const uint32_t fieldIdx,
163 uint32_t& resolvedTypeIdx) {
164 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
165 Field* field = class_linker->ResolveField(fieldIdx, method, true);
166 if (field == NULL) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700167 Thread* thread = Thread::Current();
168 if (thread->IsExceptionPending()) { // clear any exception left by resolve field
169 thread->ClearException();
170 }
Brian Carlstrom845490b2011-09-19 15:56:53 -0700171 return NULL;
172 }
173 const art::DexFile& dex_file = class_linker->
174 FindDexFile(method->GetDeclaringClass()->GetDexCache());
175 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
176 int type_idx = field_id.class_idx_;
177 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
178 // Check if storage class is the same as class referred to by type idx.
179 // They may not be if the FieldId refers a subclass, but storage is in super
180 if (field->GetDeclaringClass() == klass) {
181 resolvedTypeIdx = type_idx;
182 return field;
183 }
184 // See if we can find a dex reference for the storage class.
185 // we may not if the dex file never references the super class,
186 // but usually it will.
187 std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
188 for (size_t type_idx = 0; type_idx < dex_file.NumTypeIds(); type_idx++) {
189 const art::DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
190 if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
191 resolvedTypeIdx = type_idx;
192 return field;
193 }
194 }
195 return NULL; // resort to slow path
196}
197
buzbeeed3e9302011-09-23 17:34:19 -0700198STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700199{
buzbeee1931742011-08-28 21:15:53 -0700200 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
201 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700202 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700203 uint32_t typeIdx;
204 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700205 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700206 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700207 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700208 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700209 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
210 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700211 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
212 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
213 loadCurrMethodDirect(cUnit, r1);
214 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700215 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700216 } else {
buzbee1da522d2011-09-04 11:22:20 -0700217 // fast path
218 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700219 // Using fixed register to sync with slow path
220 int rMethod = r1;
221 oatLockTemp(cUnit, rMethod);
222 loadCurrMethodDirect(cUnit, rMethod);
223 int rBase = r0;
224 oatLockTemp(cUnit, rBase);
225 loadWordDisp(cUnit, rMethod,
226 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
227 rBase);
228 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
229 sizeof(int32_t*)* typeIdx, rBase);
230 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700231 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700232 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
233 loadWordDisp(cUnit, rSELF,
234 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
235 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700236 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700237 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
238 skipTarget->defMask = ENCODE_ALL;
239 branchOver->generic.target = (LIR*)skipTarget;
240 rlSrc = oatGetSrc(cUnit, mir, 0);
241 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700242#if ANDROID_SMP != 0
243 if (field->IsVolatile()) {
244 oatGenMemBarrier(cUnit, kST);
245 }
246#endif
buzbee1da522d2011-09-04 11:22:20 -0700247 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700248#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700249 if (field->IsVolatile()) {
250 oatGenMemBarrier(cUnit, kSY);
251 }
buzbee67bf8852011-08-17 17:51:35 -0700252#endif
buzbee1da522d2011-09-04 11:22:20 -0700253 if (isObject) {
254 markGCCard(cUnit, rlSrc.lowReg, rBase);
255 }
256 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700257 }
buzbee67bf8852011-08-17 17:51:35 -0700258}
259
buzbeeed3e9302011-09-23 17:34:19 -0700260STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700261{
buzbee1da522d2011-09-04 11:22:20 -0700262 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700263 uint32_t typeIdx;
264 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700265 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700266#if ANDROID_SMP != 0
267 bool isVolatile = (field == NULL) || field->IsVolatile();
268#else
269 bool isVolatile = false;
270#endif
271 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700272 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700273 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700274 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
275 loadCurrMethodDirect(cUnit, r1);
276 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700277 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700278 } else {
buzbee1da522d2011-09-04 11:22:20 -0700279 // fast path
280 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700281 // Using fixed register to sync with slow path
282 int rMethod = r1;
283 oatLockTemp(cUnit, rMethod);
284 loadCurrMethodDirect(cUnit, r1);
285 int rBase = r0;
286 oatLockTemp(cUnit, rBase);
287 loadWordDisp(cUnit, rMethod,
288 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
289 rBase);
290 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
291 sizeof(int32_t*)* typeIdx, rBase);
292 // TUNING: fast path should fall through
293 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
294 loadWordDisp(cUnit, rSELF,
295 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
296 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700297 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700298 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
299 skipTarget->defMask = ENCODE_ALL;
300 branchOver->generic.target = (LIR*)skipTarget;
301 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
302 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
303 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
304 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700305 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700306 }
buzbee67bf8852011-08-17 17:51:35 -0700307}
308
309
buzbeeed3e9302011-09-23 17:34:19 -0700310STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700311 RegLocation rlResult, RegLocation rlDest)
312{
buzbee1da522d2011-09-04 11:22:20 -0700313 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700314 uint32_t typeIdx;
315 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700316#if ANDROID_SMP != 0
317 bool isVolatile = (field == NULL) || field->IsVolatile();
318#else
319 bool isVolatile = false;
320#endif
buzbee6181f792011-09-29 11:14:04 -0700321 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700322 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700323 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700324 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700325 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
326 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700327 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700328 RegLocation rlResult = oatGetReturnWide(cUnit);
329 storeValueWide(cUnit, rlDest, rlResult);
330 } else {
buzbee1da522d2011-09-04 11:22:20 -0700331 // Fast path
332 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700333 // Using fixed register to sync with slow path
334 int rMethod = r1;
335 oatLockTemp(cUnit, rMethod);
336 loadCurrMethodDirect(cUnit, rMethod);
337 int rBase = r0;
338 oatLockTemp(cUnit, rBase);
339 loadWordDisp(cUnit, rMethod,
340 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
341 rBase);
342 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
343 sizeof(int32_t*)* typeIdx, rBase);
344 // TUNING: fast path should fall through
345 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
346 loadWordDisp(cUnit, rSELF,
347 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
348 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700349 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700350 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
351 skipTarget->defMask = ENCODE_ALL;
352 branchOver->generic.target = (LIR*)skipTarget;
353 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
354 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700355 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
356 rlResult.highReg, INVALID_SREG);
357 oatFreeTemp(cUnit, rBase);
358 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700359 }
buzbee67bf8852011-08-17 17:51:35 -0700360}
361
buzbeeed3e9302011-09-23 17:34:19 -0700362STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700363 RegLocation rlResult, RegLocation rlDest)
364{
buzbee1da522d2011-09-04 11:22:20 -0700365 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700366 uint32_t typeIdx;
367 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700368 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
369 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700370 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700371 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700372 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700373 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700374 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
375 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700376 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
377 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
378 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700379 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700380 RegLocation rlResult = oatGetReturn(cUnit);
381 storeValue(cUnit, rlDest, rlResult);
382 } else {
buzbee1da522d2011-09-04 11:22:20 -0700383 // Fast path
384 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700385 // Using fixed register to sync with slow path
386 int rMethod = r1;
387 oatLockTemp(cUnit, rMethod);
388 loadCurrMethodDirect(cUnit, rMethod);
389 int rBase = r0;
390 oatLockTemp(cUnit, rBase);
391 loadWordDisp(cUnit, rMethod,
392 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
393 rBase);
394 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
395 sizeof(int32_t*)* typeIdx, rBase);
396 // TUNING: fast path should fall through
397 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
398 loadWordDisp(cUnit, rSELF,
399 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
400 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700401 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700402 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
403 skipTarget->defMask = ENCODE_ALL;
404 branchOver->generic.target = (LIR*)skipTarget;
405 rlDest = oatGetDest(cUnit, mir, 0);
406 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700407#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700408 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700409 oatGenMemBarrier(cUnit, kSY);
410 }
buzbee67bf8852011-08-17 17:51:35 -0700411#endif
buzbee1da522d2011-09-04 11:22:20 -0700412 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
413 oatFreeTemp(cUnit, rBase);
414 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700415 }
buzbee67bf8852011-08-17 17:51:35 -0700416}
417
buzbee561227c2011-09-02 15:28:19 -0700418typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
419 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700420
421/*
422 * Bit of a hack here - in leiu of a real scheduling pass,
423 * emit the next instruction in static & direct invoke sequences.
424 */
buzbeeed3e9302011-09-23 17:34:19 -0700425STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700426 DecodedInstruction* dInsn, int state,
427 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700428{
buzbee561227c2011-09-02 15:28:19 -0700429 DCHECK(rollback == NULL);
430 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700431 switch(state) {
432 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700433 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700434 break;
buzbee561227c2011-09-02 15:28:19 -0700435 case 1: // Get method->code_and_direct_methods_
436 loadWordDisp(cUnit, r0,
437 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
438 r0);
buzbee67bf8852011-08-17 17:51:35 -0700439 break;
buzbee561227c2011-09-02 15:28:19 -0700440 case 2: // Grab target method* and target code_
441 loadWordDisp(cUnit, r0,
442 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
443 loadWordDisp(cUnit, r0,
444 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700445 break;
446 default:
447 return -1;
448 }
449 return state + 1;
450}
451
buzbee67bf8852011-08-17 17:51:35 -0700452/*
453 * Bit of a hack here - in leiu of a real scheduling pass,
454 * emit the next instruction in a virtual invoke sequence.
455 * We can use rLR as a temp prior to target address loading
456 * Note also that we'll load the first argument ("this") into
457 * r1 here rather than the standard loadArgRegs.
458 */
buzbeeed3e9302011-09-23 17:34:19 -0700459STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700460 DecodedInstruction* dInsn, int state,
461 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700462{
buzbee561227c2011-09-02 15:28:19 -0700463 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700464 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700465 /*
466 * This is the fast path in which the target virtual method is
467 * fully resolved at compile time.
468 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700469 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
470 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -0700471 CHECK(baseMethod != NULL);
472 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700473 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700474 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700475 rlArg = oatGetSrc(cUnit, mir, 0);
476 loadValueDirectFixed(cUnit, rlArg, r1);
477 break;
buzbee561227c2011-09-02 15:28:19 -0700478 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700479 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700480 // get this->klass_ [use r1, set rLR]
481 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700482 break;
buzbee561227c2011-09-02 15:28:19 -0700483 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
484 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700485 break;
buzbee561227c2011-09-02 15:28:19 -0700486 case 3: // Get target method [use rLR, set r0]
487 loadWordDisp(cUnit, rLR, (target_idx * 4) +
488 art::Array::DataOffset().Int32Value(), r0);
489 break;
490 case 4: // Get the target compiled code address [uses r0, sets rLR]
491 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700492 break;
493 default:
494 return -1;
495 }
496 return state + 1;
497}
498
buzbeeed3e9302011-09-23 17:34:19 -0700499STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700500 DecodedInstruction* dInsn, int state,
501 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700502{
503 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700504 ArmLIR* skipBranch;
505 ArmLIR* skipTarget;
506 /*
507 * This handles the case in which the base method is not fully
508 * resolved at compile time. We must generate code to test
509 * for resolution a run time, bail to the slow path if not to
510 * fill in all the tables. In the latter case, we'll restart at
511 * at the beginning of the sequence.
512 */
buzbee7b1b86d2011-08-26 18:59:10 -0700513 switch(state) {
514 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700515 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700516 break;
buzbee561227c2011-09-02 15:28:19 -0700517 case 1: // Get method->dex_cache_resolved_methods_
518 loadWordDisp(cUnit, r0,
519 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700520 break;
buzbee561227c2011-09-02 15:28:19 -0700521 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
522 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
523 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700524 break;
buzbee561227c2011-09-02 15:28:19 -0700525 case 3: // Resolved?
526 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
527 // Slowest path, bail to helper, rollback and retry
528 loadWordDisp(cUnit, rSELF,
529 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
530 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700531 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700532 genUnconditionalBranch(cUnit, rollback);
533 // Resume normal slow path
534 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
535 skipTarget->defMask = ENCODE_ALL;
536 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700537 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700538 loadBaseDisp(cUnit, mir, rLR,
539 Method::GetMethodIndexOffset().Int32Value(), r0,
540 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700541 // Load "this" [set r1]
542 rlArg = oatGetSrc(cUnit, mir, 0);
543 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700544 break;
545 case 4:
546 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700547 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700548 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700549 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700550 break;
buzbee561227c2011-09-02 15:28:19 -0700551 case 5:
552 // get this->klass_->vtable_ [usr rLR, set rLR]
553 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700554 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700555 // In load shadow fold vtable_ object header size into method_index_
556 opRegImm(cUnit, kOpAdd, r0,
557 art::Array::DataOffset().Int32Value() / 4);
558 // Get target Method*
559 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
560 break;
561 case 6: // Get the target compiled code address [uses r0, sets rLR]
562 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700563 break;
564 default:
565 return -1;
566 }
567 return state + 1;
568}
569
buzbeeed3e9302011-09-23 17:34:19 -0700570STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700571 DecodedInstruction* dInsn, int callState,
572 NextCallInsn nextCallInsn, ArmLIR* rollback,
573 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700574{
buzbeec0ecd652011-09-25 18:11:54 -0700575 int nextReg = r1;
576 int nextArg = 0;
577 if (skipThis) {
578 nextReg++;
579 nextArg++;
580 }
581 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
582 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
583 rlArg = oatUpdateRawLoc(cUnit, rlArg);
584 if (rlArg.wide && (nextReg <= r2)) {
585 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
586 nextReg++;
587 nextArg++;
588 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700589 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700590 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700591 }
buzbeec0ecd652011-09-25 18:11:54 -0700592 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700593 }
594 return callState;
595}
596
buzbee4a3164f2011-09-03 11:25:10 -0700597// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700598STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700599 DecodedInstruction* dInsn, int state,
600 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700601{
buzbee510c6052011-10-27 10:47:20 -0700602 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700603 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700604 case 0: // Load trampoline target
605 loadWordDisp(cUnit, rSELF,
606 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
607 rLR);
608 // Load r0 with method index
609 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700610 break;
buzbee67bf8852011-08-17 17:51:35 -0700611 default:
612 return -1;
613 }
614 return state + 1;
615}
616
buzbee67bf8852011-08-17 17:51:35 -0700617/*
618 * Interleave launch code for INVOKE_SUPER. See comments
619 * for nextVCallIns.
620 */
buzbeeed3e9302011-09-23 17:34:19 -0700621STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700622 DecodedInstruction* dInsn, int state,
623 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700624{
buzbee4a3164f2011-09-03 11:25:10 -0700625 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700626 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700627 /*
628 * This is the fast path in which the target virtual method is
629 * fully resolved at compile time. Note also that this path assumes
630 * that the check to verify that the target method index falls
631 * within the size of the super's vtable has been done at compile-time.
632 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700633 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
634 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700635 CHECK(baseMethod != NULL);
636 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
637 CHECK(superClass != NULL);
638 int32_t target_idx = baseMethod->GetMethodIndex();
639 CHECK(superClass->GetVTable()->GetLength() > target_idx);
640 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
641 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700642 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700643 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700644 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700645 // Load "this" [set r1]
646 rlArg = oatGetSrc(cUnit, mir, 0);
647 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700648 // Get method->declaring_class_ [use r0, set rLR]
649 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
650 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700651 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700652 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700653 break;
654 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
655 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
656 rLR);
657 break;
658 case 2: // Get ...->super_class_->vtable [u/s rLR]
659 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
660 break;
661 case 3: // Get target method [use rLR, set r0]
662 loadWordDisp(cUnit, rLR, (target_idx * 4) +
663 art::Array::DataOffset().Int32Value(), r0);
664 break;
665 case 4: // Get the target compiled code address [uses r0, sets rLR]
666 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
667 break;
buzbee67bf8852011-08-17 17:51:35 -0700668 default:
669 return -1;
670 }
buzbee4a3164f2011-09-03 11:25:10 -0700671 return state + 1;
672}
673
674/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700675STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700676 DecodedInstruction* dInsn, int state,
677 ArmLIR* rollback)
678{
buzbee4a3164f2011-09-03 11:25:10 -0700679 RegLocation rlArg;
680 ArmLIR* skipBranch;
681 ArmLIR* skipTarget;
682 int tReg;
683 /*
684 * This handles the case in which the base method is not fully
685 * resolved at compile time. We must generate code to test
686 * for resolution a run time, bail to the slow path if not to
687 * fill in all the tables. In the latter case, we'll restart at
688 * at the beginning of the sequence.
689 */
690 switch(state) {
691 case 0: // Get the current Method* [sets r0]
692 loadCurrMethodDirect(cUnit, r0);
693 break;
694 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
695 loadWordDisp(cUnit, r0,
696 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
697 break;
698 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
699 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
700 art::Array::DataOffset().Int32Value(), rLR);
701 break;
702 case 3: // Resolved?
703 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
704 // Slowest path, bail to helper, rollback and retry
705 loadWordDisp(cUnit, rSELF,
706 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
707 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700708 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700709 genUnconditionalBranch(cUnit, rollback);
710 // Resume normal slow path
711 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
712 skipTarget->defMask = ENCODE_ALL;
713 skipBranch->generic.target = (LIR*)skipTarget;
714 // Get base_method->method_index [usr rLR, set rLR]
715 loadBaseDisp(cUnit, mir, rLR,
716 Method::GetMethodIndexOffset().Int32Value(), rLR,
717 kUnsignedHalf, INVALID_SREG);
718 // Load "this" [set r1]
719 rlArg = oatGetSrc(cUnit, mir, 0);
720 loadValueDirectFixed(cUnit, rlArg, r1);
721 // Load curMethod->declaring_class_ [uses r0, sets r0]
722 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
723 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700724 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700725 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700726 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700727 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
728 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700729 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700730 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700731 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700732 // Range check, throw NSM on failure
733 tReg = oatAllocTemp(cUnit);
734 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
735 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700736 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
737 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700738 oatFreeTemp(cUnit, tReg);
739 }
buzbee6a0f7f52011-09-05 16:14:20 -0700740 // Adjust vtable_ base past object header
741 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700742 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700743 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700744 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700745 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700746 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
747 break;
748 default:
749 return -1;
750 }
buzbee67bf8852011-08-17 17:51:35 -0700751 return state + 1;
752}
753
754/*
755 * Load up to 5 arguments, the first three of which will be in
756 * r1 .. r3. On entry r0 contains the current method pointer,
757 * and as part of the load sequence, it must be replaced with
758 * the target method pointer. Note, this may also be called
759 * for "range" variants if the number of arguments is 5 or fewer.
760 */
buzbeeed3e9302011-09-23 17:34:19 -0700761STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700762 DecodedInstruction* dInsn, int callState,
763 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700764 NextCallInsn nextCallInsn, ArmLIR* rollback,
765 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700766{
767 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700768
769 /* If no arguments, just return */
770 if (dInsn->vA == 0)
771 return callState;
772
buzbee561227c2011-09-02 15:28:19 -0700773 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700774
buzbeec0ecd652011-09-25 18:11:54 -0700775 DCHECK_LE(dInsn->vA, 5U);
776 if (dInsn->vA > 3) {
777 uint32_t nextUse = 3;
778 //Detect special case of wide arg spanning arg3/arg4
779 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
780 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
781 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
782 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
783 rlUse2.wide) {
784 int reg;
785 // Wide spans, we need the 2nd half of uses[2].
786 rlArg = oatUpdateLocWide(cUnit, rlUse2);
787 if (rlArg.location == kLocPhysReg) {
788 reg = rlArg.highReg;
789 } else {
790 // r2 & r3 can safely be used here
791 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700792 loadWordDisp(cUnit, rSP,
793 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
buzbeec0ecd652011-09-25 18:11:54 -0700794 callState = nextCallInsn(cUnit, mir, dInsn, callState,
795 rollback);
796 }
797 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
798 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
799 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
800 nextUse++;
801 }
802 // Loop through the rest
803 while (nextUse < dInsn->vA) {
804 int lowReg;
805 int highReg;
806 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
807 rlArg = oatUpdateRawLoc(cUnit, rlArg);
808 if (rlArg.location == kLocPhysReg) {
809 lowReg = rlArg.lowReg;
810 highReg = rlArg.highReg;
811 } else {
812 lowReg = r2;
813 highReg = r3;
814 if (rlArg.wide) {
815 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
816 } else {
817 loadValueDirectFixed(cUnit, rlArg, lowReg);
818 }
819 callState = nextCallInsn(cUnit, mir, dInsn, callState,
820 rollback);
821 }
822 int outsOffset = (nextUse + 1) * 4;
823 if (rlArg.wide) {
824 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
825 nextUse += 2;
826 } else {
827 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
828 nextUse++;
829 }
buzbee561227c2011-09-02 15:28:19 -0700830 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700831 }
buzbee67bf8852011-08-17 17:51:35 -0700832 }
833
buzbeec0ecd652011-09-25 18:11:54 -0700834 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
835 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700836
buzbee67bf8852011-08-17 17:51:35 -0700837 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700838 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700839 }
840 return callState;
841}
842
843/*
844 * May have 0+ arguments (also used for jumbo). Note that
845 * source virtual registers may be in physical registers, so may
846 * need to be flushed to home location before copying. This
847 * applies to arg3 and above (see below).
848 *
849 * Two general strategies:
850 * If < 20 arguments
851 * Pass args 3-18 using vldm/vstm block copy
852 * Pass arg0, arg1 & arg2 in r1-r3
853 * If 20+ arguments
854 * Pass args arg19+ using memcpy block copy
855 * Pass arg0, arg1 & arg2 in r1-r3
856 *
857 */
buzbeeed3e9302011-09-23 17:34:19 -0700858STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700859 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700860 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700861 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700862{
863 int firstArg = dInsn->vC;
864 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700865
buzbee67bf8852011-08-17 17:51:35 -0700866 // If we can treat it as non-range (Jumbo ops will use range form)
867 if (numArgs <= 5)
868 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700869 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700870 /*
871 * Make sure range list doesn't span the break between in normal
872 * Dalvik vRegs and the ins.
873 */
buzbee1b4c8592011-08-31 10:43:51 -0700874 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700875 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700876 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
877 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700878 }
879
880 /*
881 * First load the non-register arguments. Both forms expect all
882 * of the source arguments to be in their home frame location, so
883 * scan the sReg names and flush any that have been promoted to
884 * frame backing storage.
885 */
886 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700887 for (int nextArg = 0; nextArg < numArgs;) {
888 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700889 if (loc.wide) {
890 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700891 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700892 storeBaseDispWide(cUnit, rSP,
893 oatSRegOffset(cUnit, loc.sRegLow),
894 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700895 }
buzbeec0ecd652011-09-25 18:11:54 -0700896 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700897 } else {
898 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700899 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700900 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
901 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700902 }
buzbeec0ecd652011-09-25 18:11:54 -0700903 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700904 }
905 }
906
buzbee67bc2362011-10-11 18:08:40 -0700907 int startOffset = oatSRegOffset(cUnit,
908 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700909 int outsOffset = 4 /* Method* */ + (3 * 4);
910 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700911 // Generate memcpy
912 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
913 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700914 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
915 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700916 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700917 // Restore Method*
918 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700919 } else {
920 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700921 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700922 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700923 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700924 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
925 //TUNING: loosen barrier
926 ld->defMask = ENCODE_ALL;
927 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700928 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700929 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700930 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700931 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
932 setMemRefType(st, false /* isLoad */, kDalvikReg);
933 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700934 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700935 }
936
buzbeec0ecd652011-09-25 18:11:54 -0700937 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
938 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700939
buzbee561227c2011-09-02 15:28:19 -0700940 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee99f27232011-10-05 12:56:36 -0700941 if (pcrLabel) {
942 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
943 }
buzbee67bf8852011-08-17 17:51:35 -0700944 return callState;
945}
946
buzbee2a475e72011-09-07 17:19:17 -0700947// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700948STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700949{
950 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
951 loadWordDisp(cUnit, rSELF,
952 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
953 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
954 target->defMask = -1;
955 branchOver->generic.target = (LIR*)target;
956}
buzbee2a475e72011-09-07 17:19:17 -0700957
buzbeeed3e9302011-09-23 17:34:19 -0700958STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700959 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700960{
961 DecodedInstruction* dInsn = &mir->dalvikInsn;
962 int callState = 0;
963 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700964 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700965 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700966 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700967
buzbee109bd6a2011-09-06 13:58:41 -0700968 // Explicit register usage
969 oatLockCallTemps(cUnit);
970
buzbee99f27232011-10-05 12:56:36 -0700971 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
972 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
973 int idx = mir->dalvikInsn.vB;
974 Method* target = cUnit->method->GetDexCacheResolvedMethods()->Get(idx);
975 if (target) {
976 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
977 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
978 loadValueDirectFixed(cUnit, rlArg, r0);
979 loadWordDisp(cUnit, rSELF,
980 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
981 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
982 opReg(cUnit, kOpBlx, rLR);
983 oatClobberCalleeSave(cUnit);
984 return;
985 }
986 }
987 }
988
buzbee561227c2011-09-02 15:28:19 -0700989 if (range) {
990 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700991 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700992 } else {
993 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700994 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700995 }
buzbee67bf8852011-08-17 17:51:35 -0700996 // Finish up any of the call sequence not interleaved in arg loading
997 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700998 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700999 }
buzbeece302932011-10-04 14:32:18 -07001000 if (DISPLAY_MISSING_TARGETS) {
1001 genShowTarget(cUnit);
1002 }
buzbeeec5adf32011-09-11 15:25:43 -07001003 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001004 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001005}
1006
buzbee4a3164f2011-09-03 11:25:10 -07001007/*
1008 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
1009 * which will locate the target and continue on via a tail call.
1010 */
buzbeeed3e9302011-09-23 17:34:19 -07001011STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001012{
1013 DecodedInstruction* dInsn = &mir->dalvikInsn;
1014 int callState = 0;
1015 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -07001016 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001017
1018 // Explicit register usage
1019 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001020 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -07001021 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001022 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
1023 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001024 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -07001025 false);
buzbee67bf8852011-08-17 17:51:35 -07001026 else
1027 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -07001028 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -07001029 // Finish up any of the call sequence not interleaved in arg loading
1030 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001031 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001032 }
buzbeece302932011-10-04 14:32:18 -07001033 if (DISPLAY_MISSING_TARGETS) {
1034 genShowTarget(cUnit);
1035 }
buzbeeec5adf32011-09-11 15:25:43 -07001036 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001037 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001038}
1039
buzbeeed3e9302011-09-23 17:34:19 -07001040STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001041{
1042 DecodedInstruction* dInsn = &mir->dalvikInsn;
1043 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001044 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001045 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1046 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -07001047 NextCallInsn nextCallInsn;
1048 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001049 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001050
1051 // Explicit register usage
1052 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001053 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001054 Thread* thread = Thread::Current();
1055 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1056 thread->ClearException();
1057 }
buzbee4a3164f2011-09-03 11:25:10 -07001058 fastPath = false;
1059 } else {
1060 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
1061 if (superClass == NULL) {
1062 fastPath = false;
1063 } else {
1064 int32_t target_idx = baseMethod->GetMethodIndex();
1065 if (superClass->GetVTable()->GetLength() <= target_idx) {
1066 fastPath = false;
1067 } else {
1068 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1069 }
1070 }
1071 }
1072 if (fastPath) {
1073 nextCallInsn = nextSuperCallInsn;
1074 rollback = NULL;
1075 } else {
1076 nextCallInsn = nextSuperCallInsnSP;
1077 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1078 rollback->defMask = -1;
1079 }
buzbee67bf8852011-08-17 17:51:35 -07001080 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001081 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001082 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001083 else
buzbeec0ecd652011-09-25 18:11:54 -07001084 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001085 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001086 // Finish up any of the call sequence not interleaved in arg loading
1087 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001088 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001089 }
buzbeece302932011-10-04 14:32:18 -07001090 if (DISPLAY_MISSING_TARGETS) {
1091 genShowTarget(cUnit);
1092 }
buzbeeec5adf32011-09-11 15:25:43 -07001093 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001094 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001095}
1096
buzbeeed3e9302011-09-23 17:34:19 -07001097STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001098{
1099 DecodedInstruction* dInsn = &mir->dalvikInsn;
1100 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001101 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001102 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1103 Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -07001104 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001105 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee7b1b86d2011-08-26 18:59:10 -07001106
buzbee109bd6a2011-09-06 13:58:41 -07001107 // Explicit register usage
1108 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001109 if (SLOW_INVOKE_PATH || method == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001110 Thread* thread = Thread::Current();
1111 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1112 thread->ClearException();
1113 }
buzbee561227c2011-09-02 15:28:19 -07001114 // Slow path
1115 nextCallInsn = nextVCallInsnSP;
1116 // If we need a slow-path callout, we'll restart here
1117 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1118 rollback->defMask = -1;
1119 } else {
1120 // Fast path
1121 nextCallInsn = nextVCallInsn;
1122 rollback = NULL;
1123 }
buzbee67bf8852011-08-17 17:51:35 -07001124 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001125 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001126 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001127 else
buzbeec0ecd652011-09-25 18:11:54 -07001128 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001129 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001130 // Finish up any of the call sequence not interleaved in arg loading
1131 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001132 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001133 }
buzbeece302932011-10-04 14:32:18 -07001134 if (DISPLAY_MISSING_TARGETS) {
1135 genShowTarget(cUnit);
1136 }
buzbeeec5adf32011-09-11 15:25:43 -07001137 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001138 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001139}
1140
buzbeeed3e9302011-09-23 17:34:19 -07001141STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001142 BasicBlock* bb, ArmLIR* labelList)
1143{
1144 bool res = false; // Assume success
1145 RegLocation rlSrc[3];
1146 RegLocation rlDest = badLoc;
1147 RegLocation rlResult = badLoc;
1148 Opcode opcode = mir->dalvikInsn.opcode;
1149
1150 /* Prep Src and Dest locations */
1151 int nextSreg = 0;
1152 int nextLoc = 0;
1153 int attrs = oatDataFlowAttributes[opcode];
1154 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1155 if (attrs & DF_UA) {
1156 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1157 nextSreg++;
1158 } else if (attrs & DF_UA_WIDE) {
1159 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1160 nextSreg + 1);
1161 nextSreg+= 2;
1162 }
1163 if (attrs & DF_UB) {
1164 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1165 nextSreg++;
1166 } else if (attrs & DF_UB_WIDE) {
1167 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1168 nextSreg + 1);
1169 nextSreg+= 2;
1170 }
1171 if (attrs & DF_UC) {
1172 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1173 } else if (attrs & DF_UC_WIDE) {
1174 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1175 nextSreg + 1);
1176 }
1177 if (attrs & DF_DA) {
1178 rlDest = oatGetDest(cUnit, mir, 0);
1179 } else if (attrs & DF_DA_WIDE) {
1180 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1181 }
1182
1183 switch(opcode) {
1184 case OP_NOP:
1185 break;
1186
1187 case OP_MOVE_EXCEPTION:
1188 int exOffset;
1189 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001190 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001191 resetReg = oatAllocTemp(cUnit);
1192 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1193 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1194 loadConstant(cUnit, resetReg, 0);
1195 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1196 storeValue(cUnit, rlDest, rlResult);
1197 break;
1198
1199 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -07001200 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001201 break;
1202
1203 case OP_RETURN:
1204 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -07001205 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001206 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001207 break;
1208
1209 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -07001210 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001211 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001212 break;
1213
1214 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001215 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001216 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001217 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001218 break;
1219
1220 case OP_MOVE_RESULT:
1221 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001222 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001223 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001224 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001225 break;
1226
1227 case OP_MOVE:
1228 case OP_MOVE_OBJECT:
1229 case OP_MOVE_16:
1230 case OP_MOVE_OBJECT_16:
1231 case OP_MOVE_FROM16:
1232 case OP_MOVE_OBJECT_FROM16:
1233 storeValue(cUnit, rlDest, rlSrc[0]);
1234 break;
1235
1236 case OP_MOVE_WIDE:
1237 case OP_MOVE_WIDE_16:
1238 case OP_MOVE_WIDE_FROM16:
1239 storeValueWide(cUnit, rlDest, rlSrc[0]);
1240 break;
1241
1242 case OP_CONST:
1243 case OP_CONST_4:
1244 case OP_CONST_16:
1245 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1246 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1247 storeValue(cUnit, rlDest, rlResult);
1248 break;
1249
1250 case OP_CONST_HIGH16:
1251 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1252 loadConstantNoClobber(cUnit, rlResult.lowReg,
1253 mir->dalvikInsn.vB << 16);
1254 storeValue(cUnit, rlDest, rlResult);
1255 break;
1256
1257 case OP_CONST_WIDE_16:
1258 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001259 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1260 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1261 mir->dalvikInsn.vB,
1262 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001263 storeValueWide(cUnit, rlDest, rlResult);
1264 break;
1265
1266 case OP_CONST_WIDE:
1267 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1268 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001269 mir->dalvikInsn.vB_wide & 0xffffffff,
1270 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001271 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001272 break;
1273
1274 case OP_CONST_WIDE_HIGH16:
1275 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1276 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1277 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001278 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001279 break;
1280
1281 case OP_MONITOR_ENTER:
1282 genMonitorEnter(cUnit, mir, rlSrc[0]);
1283 break;
1284
1285 case OP_MONITOR_EXIT:
1286 genMonitorExit(cUnit, mir, rlSrc[0]);
1287 break;
1288
1289 case OP_CHECK_CAST:
1290 genCheckCast(cUnit, mir, rlSrc[0]);
1291 break;
1292
1293 case OP_INSTANCE_OF:
1294 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1295 break;
1296
1297 case OP_NEW_INSTANCE:
1298 genNewInstance(cUnit, mir, rlDest);
1299 break;
1300
1301 case OP_THROW:
1302 genThrow(cUnit, mir, rlSrc[0]);
1303 break;
1304
buzbee5ade1d22011-09-09 14:44:52 -07001305 case OP_THROW_VERIFICATION_ERROR:
1306 loadWordDisp(cUnit, rSELF,
1307 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1308 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1309 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001310 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001311 break;
1312
buzbee67bf8852011-08-17 17:51:35 -07001313 case OP_ARRAY_LENGTH:
1314 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001315 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001316 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001317 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001318 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1319 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1320 rlResult.lowReg);
1321 storeValue(cUnit, rlDest, rlResult);
1322 break;
1323
1324 case OP_CONST_STRING:
1325 case OP_CONST_STRING_JUMBO:
1326 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1327 break;
1328
1329 case OP_CONST_CLASS:
1330 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1331 break;
1332
1333 case OP_FILL_ARRAY_DATA:
1334 genFillArrayData(cUnit, mir, rlSrc[0]);
1335 break;
1336
1337 case OP_FILLED_NEW_ARRAY:
1338 genFilledNewArray(cUnit, mir, false /* not range */);
1339 break;
1340
1341 case OP_FILLED_NEW_ARRAY_RANGE:
1342 genFilledNewArray(cUnit, mir, true /* range */);
1343 break;
1344
1345 case OP_NEW_ARRAY:
1346 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1347 break;
1348
1349 case OP_GOTO:
1350 case OP_GOTO_16:
1351 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001352 if (bb->taken->startOffset <= mir->offset) {
1353 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001354 }
1355 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1356 break;
1357
1358 case OP_PACKED_SWITCH:
1359 genPackedSwitch(cUnit, mir, rlSrc[0]);
1360 break;
1361
1362 case OP_SPARSE_SWITCH:
1363 genSparseSwitch(cUnit, mir, rlSrc[0]);
1364 break;
1365
1366 case OP_CMPL_FLOAT:
1367 case OP_CMPG_FLOAT:
1368 case OP_CMPL_DOUBLE:
1369 case OP_CMPG_DOUBLE:
1370 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1371 break;
1372
1373 case OP_CMP_LONG:
1374 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1375 break;
1376
1377 case OP_IF_EQ:
1378 case OP_IF_NE:
1379 case OP_IF_LT:
1380 case OP_IF_GE:
1381 case OP_IF_GT:
1382 case OP_IF_LE: {
1383 bool backwardBranch;
1384 ArmConditionCode cond;
1385 backwardBranch = (bb->taken->startOffset <= mir->offset);
1386 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001387 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001388 }
1389 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1390 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1391 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1392 switch(opcode) {
1393 case OP_IF_EQ:
1394 cond = kArmCondEq;
1395 break;
1396 case OP_IF_NE:
1397 cond = kArmCondNe;
1398 break;
1399 case OP_IF_LT:
1400 cond = kArmCondLt;
1401 break;
1402 case OP_IF_GE:
1403 cond = kArmCondGe;
1404 break;
1405 case OP_IF_GT:
1406 cond = kArmCondGt;
1407 break;
1408 case OP_IF_LE:
1409 cond = kArmCondLe;
1410 break;
1411 default:
1412 cond = (ArmConditionCode)0;
1413 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1414 }
1415 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1416 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1417 break;
1418 }
1419
1420 case OP_IF_EQZ:
1421 case OP_IF_NEZ:
1422 case OP_IF_LTZ:
1423 case OP_IF_GEZ:
1424 case OP_IF_GTZ:
1425 case OP_IF_LEZ: {
1426 bool backwardBranch;
1427 ArmConditionCode cond;
1428 backwardBranch = (bb->taken->startOffset <= mir->offset);
1429 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001430 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001431 }
1432 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1433 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1434 switch(opcode) {
1435 case OP_IF_EQZ:
1436 cond = kArmCondEq;
1437 break;
1438 case OP_IF_NEZ:
1439 cond = kArmCondNe;
1440 break;
1441 case OP_IF_LTZ:
1442 cond = kArmCondLt;
1443 break;
1444 case OP_IF_GEZ:
1445 cond = kArmCondGe;
1446 break;
1447 case OP_IF_GTZ:
1448 cond = kArmCondGt;
1449 break;
1450 case OP_IF_LEZ:
1451 cond = kArmCondLe;
1452 break;
1453 default:
1454 cond = (ArmConditionCode)0;
1455 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1456 }
1457 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1458 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1459 break;
1460 }
1461
1462 case OP_AGET_WIDE:
1463 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1464 break;
1465 case OP_AGET:
1466 case OP_AGET_OBJECT:
1467 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1468 break;
1469 case OP_AGET_BOOLEAN:
1470 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1471 rlDest, 0);
1472 break;
1473 case OP_AGET_BYTE:
1474 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1475 break;
1476 case OP_AGET_CHAR:
1477 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1478 rlDest, 1);
1479 break;
1480 case OP_AGET_SHORT:
1481 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1482 break;
1483 case OP_APUT_WIDE:
1484 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1485 break;
1486 case OP_APUT:
1487 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1488 break;
1489 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001490 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001491 break;
1492 case OP_APUT_SHORT:
1493 case OP_APUT_CHAR:
1494 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1495 rlSrc[0], 1);
1496 break;
1497 case OP_APUT_BYTE:
1498 case OP_APUT_BOOLEAN:
1499 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1500 rlSrc[0], 0);
1501 break;
1502
1503 case OP_IGET_WIDE:
1504 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001505 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001506 break;
1507
1508 case OP_IGET:
1509 case OP_IGET_VOLATILE:
1510 case OP_IGET_OBJECT:
1511 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001512 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001513 break;
1514
1515 case OP_IGET_BOOLEAN:
1516 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001517 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001518 break;
1519
1520 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001521 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001522 break;
1523
1524 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001525 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001526 break;
1527
1528 case OP_IPUT_WIDE:
1529 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001530 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001531 break;
1532
1533 case OP_IPUT_OBJECT:
1534 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001535 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001536 break;
1537
1538 case OP_IPUT:
1539 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001540 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001541 break;
1542
1543 case OP_IPUT_BOOLEAN:
1544 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001545 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001546 break;
1547
1548 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001549 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001550 break;
1551
1552 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001553 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001554 break;
1555
1556 case OP_SGET:
1557 case OP_SGET_OBJECT:
1558 case OP_SGET_BOOLEAN:
1559 case OP_SGET_BYTE:
1560 case OP_SGET_CHAR:
1561 case OP_SGET_SHORT:
1562 genSget(cUnit, mir, rlResult, rlDest);
1563 break;
1564
1565 case OP_SGET_WIDE:
1566 genSgetWide(cUnit, mir, rlResult, rlDest);
1567 break;
1568
1569 case OP_SPUT:
1570 case OP_SPUT_OBJECT:
1571 case OP_SPUT_BOOLEAN:
1572 case OP_SPUT_BYTE:
1573 case OP_SPUT_CHAR:
1574 case OP_SPUT_SHORT:
1575 genSput(cUnit, mir, rlSrc[0]);
1576 break;
1577
1578 case OP_SPUT_WIDE:
1579 genSputWide(cUnit, mir, rlSrc[0]);
1580 break;
1581
1582 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001583 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1584 true /*range*/);
1585 break;
buzbee67bf8852011-08-17 17:51:35 -07001586 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001587 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1588 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001589 break;
1590
1591 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001592 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1593 false /*range*/);
1594 break;
buzbee67bf8852011-08-17 17:51:35 -07001595 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001596 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1597 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001598 break;
1599
1600 case OP_INVOKE_VIRTUAL:
1601 case OP_INVOKE_VIRTUAL_RANGE:
1602 genInvokeVirtual(cUnit, mir);
1603 break;
1604
1605 case OP_INVOKE_SUPER:
1606 case OP_INVOKE_SUPER_RANGE:
1607 genInvokeSuper(cUnit, mir);
1608 break;
1609
1610 case OP_INVOKE_INTERFACE:
1611 case OP_INVOKE_INTERFACE_RANGE:
1612 genInvokeInterface(cUnit, mir);
1613 break;
1614
1615 case OP_NEG_INT:
1616 case OP_NOT_INT:
1617 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1618 break;
1619
1620 case OP_NEG_LONG:
1621 case OP_NOT_LONG:
1622 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1623 break;
1624
1625 case OP_NEG_FLOAT:
1626 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1627 break;
1628
1629 case OP_NEG_DOUBLE:
1630 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1631 break;
1632
1633 case OP_INT_TO_LONG:
1634 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1635 if (rlSrc[0].location == kLocPhysReg) {
1636 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1637 } else {
1638 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1639 }
1640 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1641 rlResult.lowReg, 31);
1642 storeValueWide(cUnit, rlDest, rlResult);
1643 break;
1644
1645 case OP_LONG_TO_INT:
1646 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1647 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1648 storeValue(cUnit, rlDest, rlSrc[0]);
1649 break;
1650
1651 case OP_INT_TO_BYTE:
1652 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1653 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1654 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1655 storeValue(cUnit, rlDest, rlResult);
1656 break;
1657
1658 case OP_INT_TO_SHORT:
1659 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1660 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1661 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1662 storeValue(cUnit, rlDest, rlResult);
1663 break;
1664
1665 case OP_INT_TO_CHAR:
1666 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1667 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1668 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1669 storeValue(cUnit, rlDest, rlResult);
1670 break;
1671
1672 case OP_INT_TO_FLOAT:
1673 case OP_INT_TO_DOUBLE:
1674 case OP_LONG_TO_FLOAT:
1675 case OP_LONG_TO_DOUBLE:
1676 case OP_FLOAT_TO_INT:
1677 case OP_FLOAT_TO_LONG:
1678 case OP_FLOAT_TO_DOUBLE:
1679 case OP_DOUBLE_TO_INT:
1680 case OP_DOUBLE_TO_LONG:
1681 case OP_DOUBLE_TO_FLOAT:
1682 genConversion(cUnit, mir);
1683 break;
1684
1685 case OP_ADD_INT:
1686 case OP_SUB_INT:
1687 case OP_MUL_INT:
1688 case OP_DIV_INT:
1689 case OP_REM_INT:
1690 case OP_AND_INT:
1691 case OP_OR_INT:
1692 case OP_XOR_INT:
1693 case OP_SHL_INT:
1694 case OP_SHR_INT:
1695 case OP_USHR_INT:
1696 case OP_ADD_INT_2ADDR:
1697 case OP_SUB_INT_2ADDR:
1698 case OP_MUL_INT_2ADDR:
1699 case OP_DIV_INT_2ADDR:
1700 case OP_REM_INT_2ADDR:
1701 case OP_AND_INT_2ADDR:
1702 case OP_OR_INT_2ADDR:
1703 case OP_XOR_INT_2ADDR:
1704 case OP_SHL_INT_2ADDR:
1705 case OP_SHR_INT_2ADDR:
1706 case OP_USHR_INT_2ADDR:
1707 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1708 break;
1709
1710 case OP_ADD_LONG:
1711 case OP_SUB_LONG:
1712 case OP_MUL_LONG:
1713 case OP_DIV_LONG:
1714 case OP_REM_LONG:
1715 case OP_AND_LONG:
1716 case OP_OR_LONG:
1717 case OP_XOR_LONG:
1718 case OP_ADD_LONG_2ADDR:
1719 case OP_SUB_LONG_2ADDR:
1720 case OP_MUL_LONG_2ADDR:
1721 case OP_DIV_LONG_2ADDR:
1722 case OP_REM_LONG_2ADDR:
1723 case OP_AND_LONG_2ADDR:
1724 case OP_OR_LONG_2ADDR:
1725 case OP_XOR_LONG_2ADDR:
1726 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1727 break;
1728
buzbee67bf8852011-08-17 17:51:35 -07001729 case OP_SHL_LONG:
1730 case OP_SHR_LONG:
1731 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001732 case OP_SHL_LONG_2ADDR:
1733 case OP_SHR_LONG_2ADDR:
1734 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001735 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1736 break;
1737
1738 case OP_ADD_FLOAT:
1739 case OP_SUB_FLOAT:
1740 case OP_MUL_FLOAT:
1741 case OP_DIV_FLOAT:
1742 case OP_REM_FLOAT:
1743 case OP_ADD_FLOAT_2ADDR:
1744 case OP_SUB_FLOAT_2ADDR:
1745 case OP_MUL_FLOAT_2ADDR:
1746 case OP_DIV_FLOAT_2ADDR:
1747 case OP_REM_FLOAT_2ADDR:
1748 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1749 break;
1750
1751 case OP_ADD_DOUBLE:
1752 case OP_SUB_DOUBLE:
1753 case OP_MUL_DOUBLE:
1754 case OP_DIV_DOUBLE:
1755 case OP_REM_DOUBLE:
1756 case OP_ADD_DOUBLE_2ADDR:
1757 case OP_SUB_DOUBLE_2ADDR:
1758 case OP_MUL_DOUBLE_2ADDR:
1759 case OP_DIV_DOUBLE_2ADDR:
1760 case OP_REM_DOUBLE_2ADDR:
1761 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1762 break;
1763
1764 case OP_RSUB_INT:
1765 case OP_ADD_INT_LIT16:
1766 case OP_MUL_INT_LIT16:
1767 case OP_DIV_INT_LIT16:
1768 case OP_REM_INT_LIT16:
1769 case OP_AND_INT_LIT16:
1770 case OP_OR_INT_LIT16:
1771 case OP_XOR_INT_LIT16:
1772 case OP_ADD_INT_LIT8:
1773 case OP_RSUB_INT_LIT8:
1774 case OP_MUL_INT_LIT8:
1775 case OP_DIV_INT_LIT8:
1776 case OP_REM_INT_LIT8:
1777 case OP_AND_INT_LIT8:
1778 case OP_OR_INT_LIT8:
1779 case OP_XOR_INT_LIT8:
1780 case OP_SHL_INT_LIT8:
1781 case OP_SHR_INT_LIT8:
1782 case OP_USHR_INT_LIT8:
1783 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1784 break;
1785
1786 default:
1787 res = true;
1788 }
1789 return res;
1790}
1791
buzbeeed3e9302011-09-23 17:34:19 -07001792STATIC const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001793 "kMirOpPhi",
1794 "kMirOpNullNRangeUpCheck",
1795 "kMirOpNullNRangeDownCheck",
1796 "kMirOpLowerBound",
1797 "kMirOpPunt",
1798 "kMirOpCheckInlinePrediction",
1799};
1800
1801/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001802STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001803{
1804 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1805 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1806 strcpy(msg, extendedMIROpNames[opOffset]);
1807 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1808
1809 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1810 case kMirOpPhi: {
1811 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1812 op->flags.isNop = true;
1813 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1814 break;
1815 }
1816 default:
1817 break;
1818 }
1819}
1820
buzbee67bc2362011-10-11 18:08:40 -07001821/*
1822 * If there are any ins passed in registers that have not been promoted
1823 * to a callee-save register, flush them to the frame. Perform intial
1824 * assignment of promoted arguments.
1825 */
buzbeeed3e9302011-09-23 17:34:19 -07001826STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001827{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001828 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001829 return;
buzbee67bc2362011-10-11 18:08:40 -07001830 int firstArgReg = r1;
1831 int lastArgReg = r3;
1832 int startVReg = cUnit->method->NumRegisters() -
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001833 cUnit->method->NumIns();
buzbee8febc582011-10-25 12:39:20 -07001834 /*
1835 * Arguments passed in registers should be flushed
1836 * to their backing locations in the frame for now.
1837 * Also, we need to do initial assignment for promoted
1838 * arguments. NOTE: an older version of dx had an issue
1839 * in which it would reuse static method argument registers.
1840 * This could result in the same Dalvik virtual register
1841 * being promoted to both core and fp regs. In those
1842 * cases, copy argument to both. This will be uncommon
1843 * enough that it isn't worth attempting to optimize.
1844 */
buzbee67bc2362011-10-11 18:08:40 -07001845 for (int i = 0; i < cUnit->method->NumIns(); i++) {
1846 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001847 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001848 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001849 if (vMap.coreLocation == kLocPhysReg) {
1850 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001851 }
1852 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001853 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1854 }
1855 // Also put a copy in memory in case we're partially promoted
1856 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1857 firstArgReg + i, kWord);
1858 } else {
buzbee8febc582011-10-25 12:39:20 -07001859 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001860 if (vMap.coreLocation == kLocPhysReg) {
1861 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1862 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001863 }
1864 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001865 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1866 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001867 }
1868 }
buzbee67bf8852011-08-17 17:51:35 -07001869 }
1870}
1871
1872/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001873STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001874{
1875 MIR* mir;
1876 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1877 int blockId = bb->id;
1878
1879 cUnit->curBlock = bb;
1880 labelList[blockId].operands[0] = bb->startOffset;
1881
1882 /* Insert the block label */
1883 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1884 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1885
buzbee6181f792011-09-29 11:14:04 -07001886 /* Reset local optimization data on block boundaries */
1887 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001888 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001889 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001890
1891 ArmLIR* headLIR = NULL;
1892
buzbeebbaf8942011-10-02 13:08:29 -07001893 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001894 if (bb->blockType == kEntryBlock) {
1895 /*
1896 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1897 * mechanism know so it doesn't try to use any of them when
1898 * expanding the frame or flushing. This leaves the utility
1899 * code with a single temp: r12. This should be enough.
1900 */
1901 oatLockTemp(cUnit, r0);
1902 oatLockTemp(cUnit, r1);
1903 oatLockTemp(cUnit, r2);
1904 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001905
1906 /*
1907 * We can safely skip the stack overflow check if we're
1908 * a leaf *and* our frame size < fudge factor.
1909 */
1910 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1911 ((size_t)cUnit->frameSize <
1912 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001913 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001914 if (!skipOverflowCheck) {
1915 /* Load stack limit */
1916 loadWordDisp(cUnit, rSELF,
1917 art::Thread::StackEndOffset().Int32Value(), r12);
1918 }
buzbee67bf8852011-08-17 17:51:35 -07001919 /* Spill core callee saves */
1920 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1921 /* Need to spill any FP regs? */
1922 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001923 /*
1924 * NOTE: fp spills are a little different from core spills in that
1925 * they are pushed as a contiguous block. When promoting from
1926 * the fp set, we must allocate all singles from s16..highest-promoted
1927 */
buzbee67bf8852011-08-17 17:51:35 -07001928 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1929 }
buzbeecefd1872011-09-09 09:59:52 -07001930 if (!skipOverflowCheck) {
1931 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001932 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001933 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1934 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001935 genRegCopy(cUnit, rSP, rLR); // Establish stack
1936 } else {
1937 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001938 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001939 }
buzbee67bf8852011-08-17 17:51:35 -07001940 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1941 flushIns(cUnit);
1942 oatFreeTemp(cUnit, r0);
1943 oatFreeTemp(cUnit, r1);
1944 oatFreeTemp(cUnit, r2);
1945 oatFreeTemp(cUnit, r3);
1946 } else if (bb->blockType == kExitBlock) {
1947 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07001948 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07001949 /* Need to restore any FP callee saves? */
1950 if (cUnit->numFPSpills) {
1951 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1952 }
1953 if (cUnit->coreSpillMask & (1 << rLR)) {
1954 /* Unspill rLR to rPC */
1955 cUnit->coreSpillMask &= ~(1 << rLR);
1956 cUnit->coreSpillMask |= (1 << rPC);
1957 }
1958 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1959 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1960 /* We didn't pop to rPC, so must do a bv rLR */
1961 newLIR1(cUnit, kThumbBx, rLR);
1962 }
1963 }
1964
1965 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1966
1967 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07001968 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1969 oatClobberAllRegs(cUnit);
1970 }
buzbee67bf8852011-08-17 17:51:35 -07001971
1972 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1973 oatResetDefTracking(cUnit);
1974 }
1975
1976 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1977 handleExtendedMethodMIR(cUnit, mir);
1978 continue;
1979 }
1980
1981 cUnit->currentDalvikOffset = mir->offset;
1982
1983 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1984 InstructionFormat dalvikFormat =
1985 dexGetFormatFromOpcode(dalvikOpcode);
1986
1987 ArmLIR* boundaryLIR;
1988
1989 /* Mark the beginning of a Dalvik instruction for line tracking */
1990 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1991 (int) oatGetDalvikDisassembly(
1992 &mir->dalvikInsn, ""));
1993 /* Remember the first LIR for this block */
1994 if (headLIR == NULL) {
1995 headLIR = boundaryLIR;
1996 /* Set the first boundaryLIR as a scheduling barrier */
1997 headLIR->defMask = ENCODE_ALL;
1998 }
1999
2000 /* Don't generate the SSA annotation unless verbose mode is on */
2001 if (cUnit->printMe && mir->ssaRep) {
2002 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
2003 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
2004 }
2005
2006 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
2007
2008 if (notHandled) {
2009 char buf[100];
2010 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
2011 mir->offset,
2012 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
2013 dalvikFormat);
2014 LOG(FATAL) << buf;
2015 }
2016 }
2017
2018 if (headLIR) {
2019 /*
2020 * Eliminate redundant loads/stores and delay stores into later
2021 * slots
2022 */
2023 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
2024 cUnit->lastLIRInsn);
2025
2026 /*
2027 * Generate an unconditional branch to the fallthrough block.
2028 */
2029 if (bb->fallThrough) {
2030 genUnconditionalBranch(cUnit,
2031 &labelList[bb->fallThrough->id]);
2032 }
2033 }
2034 return false;
2035}
2036
2037/*
2038 * Nop any unconditional branches that go to the next instruction.
2039 * Note: new redundant branches may be inserted later, and we'll
2040 * use a check in final instruction assembly to nop those out.
2041 */
2042void removeRedundantBranches(CompilationUnit* cUnit)
2043{
2044 ArmLIR* thisLIR;
2045
2046 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2047 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2048 thisLIR = NEXT_LIR(thisLIR)) {
2049
2050 /* Branch to the next instruction */
2051 if ((thisLIR->opcode == kThumbBUncond) ||
2052 (thisLIR->opcode == kThumb2BUncond)) {
2053 ArmLIR* nextLIR = thisLIR;
2054
2055 while (true) {
2056 nextLIR = NEXT_LIR(nextLIR);
2057
2058 /*
2059 * Is the branch target the next instruction?
2060 */
2061 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2062 thisLIR->flags.isNop = true;
2063 break;
2064 }
2065
2066 /*
2067 * Found real useful stuff between the branch and the target.
2068 * Need to explicitly check the lastLIRInsn here because it
2069 * might be the last real instruction.
2070 */
2071 if (!isPseudoOpcode(nextLIR->opcode) ||
2072 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2073 break;
2074 }
2075 }
2076 }
2077}
2078
buzbeeed3e9302011-09-23 17:34:19 -07002079STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002080{
2081 ArmLIR** suspendLabel =
2082 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2083 int numElems = cUnit->suspendLaunchpads.numUsed;
2084
2085 for (int i = 0; i < numElems; i++) {
2086 /* TUNING: move suspend count load into helper */
2087 ArmLIR* lab = suspendLabel[i];
2088 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2089 cUnit->currentDalvikOffset = lab->operands[1];
2090 oatAppendLIR(cUnit, (LIR *)lab);
2091 loadWordDisp(cUnit, rSELF,
2092 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2093 loadWordDisp(cUnit, rSELF,
2094 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2095 opReg(cUnit, kOpBlx, rLR);
2096 genUnconditionalBranch(cUnit, resumeLab);
2097 }
2098}
2099
buzbeeed3e9302011-09-23 17:34:19 -07002100STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002101{
2102 ArmLIR** throwLabel =
2103 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2104 int numElems = cUnit->throwLaunchpads.numUsed;
2105 int i;
2106
2107 for (i = 0; i < numElems; i++) {
2108 ArmLIR* lab = throwLabel[i];
2109 cUnit->currentDalvikOffset = lab->operands[1];
2110 oatAppendLIR(cUnit, (LIR *)lab);
2111 int funcOffset = 0;
2112 int v1 = lab->operands[2];
2113 int v2 = lab->operands[3];
2114 switch(lab->operands[0]) {
2115 case kArmThrowNullPointer:
2116 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2117 break;
2118 case kArmThrowArrayBounds:
2119 if (v2 != r0) {
2120 genRegCopy(cUnit, r0, v1);
2121 genRegCopy(cUnit, r1, v2);
2122 } else {
2123 if (v1 == r1) {
2124 genRegCopy(cUnit, r12, v1);
2125 genRegCopy(cUnit, r1, v2);
2126 genRegCopy(cUnit, r0, r12);
2127 } else {
2128 genRegCopy(cUnit, r1, v2);
2129 genRegCopy(cUnit, r0, v1);
2130 }
2131 }
2132 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2133 break;
2134 case kArmThrowDivZero:
2135 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2136 break;
2137 case kArmThrowVerificationError:
2138 loadConstant(cUnit, r0, v1);
2139 loadConstant(cUnit, r1, v2);
2140 funcOffset =
2141 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2142 break;
2143 case kArmThrowNegArraySize:
2144 genRegCopy(cUnit, r0, v1);
2145 funcOffset =
2146 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2147 break;
buzbee5ade1d22011-09-09 14:44:52 -07002148 case kArmThrowNoSuchMethod:
2149 genRegCopy(cUnit, r0, v1);
2150 funcOffset =
2151 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2152 break;
buzbeeec5adf32011-09-11 15:25:43 -07002153 case kArmThrowStackOverflow:
2154 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002155 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002156 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002157 opRegImm(cUnit, kOpAdd, rSP,
2158 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002159 break;
buzbee5ade1d22011-09-09 14:44:52 -07002160 default:
2161 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2162 }
2163 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002164 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002165 }
2166}
2167
buzbee67bf8852011-08-17 17:51:35 -07002168void oatMethodMIR2LIR(CompilationUnit* cUnit)
2169{
2170 /* Used to hold the labels of each block */
2171 cUnit->blockLabelList =
2172 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2173
2174 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2175 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002176 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002177
2178 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002179
2180 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002181}
2182
2183/* Common initialization routine for an architecture family */
2184bool oatArchInit()
2185{
2186 int i;
2187
2188 for (i = 0; i < kArmLast; i++) {
2189 if (EncodingMap[i].opcode != i) {
2190 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2191 " is wrong: expecting " << i << ", seeing " <<
2192 (int)EncodingMap[i].opcode;
2193 }
2194 }
2195
2196 return oatArchVariantInit();
2197}
2198
2199/* Needed by the Assembler */
2200void oatSetupResourceMasks(ArmLIR* lir)
2201{
2202 setupResourceMasks(lir);
2203}
2204
2205/* Needed by the ld/st optmizatons */
2206ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2207{
2208 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2209}
2210
2211/* Needed by the register allocator */
2212ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2213{
2214 return genRegCopy(cUnit, rDest, rSrc);
2215}
2216
2217/* Needed by the register allocator */
2218void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2219 int srcLo, int srcHi)
2220{
2221 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2222}
2223
2224void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2225 int displacement, int rSrc, OpSize size)
2226{
2227 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2228}
2229
2230void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2231 int displacement, int rSrcLo, int rSrcHi)
2232{
2233 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2234}