blob: 08a53bd80cf449e14380d0d15e87c5ffacb85b30 [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
Ian Rogers6d4d9fc2011-11-30 16:24:48 -080017#include "object_utils.h"
18
buzbeece302932011-10-04 14:32:18 -070019#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
20 (1 << kDebugDisplayMissingTargets))
Elliott Hughes1240dad2011-09-09 16:24:50 -070021
buzbee67bc2362011-10-11 18:08:40 -070022STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, INVALID_REG,
23 INVALID_REG, INVALID_SREG};
buzbee6181f792011-09-29 11:14:04 -070024
25/* Mark register usage state and return long retloc */
26STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
27{
28 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
29 oatLockTemp(cUnit, res.lowReg);
30 oatLockTemp(cUnit, res.highReg);
31 oatMarkPair(cUnit, res.lowReg, res.highReg);
32 return res;
33}
34
35STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
36{
37 RegLocation res = LOC_DALVIK_RETURN_VAL;
38 oatLockTemp(cUnit, res.lowReg);
39 return res;
40}
buzbee67bf8852011-08-17 17:51:35 -070041
buzbeedfd3d702011-08-28 12:56:51 -070042/*
43 * Let helper function take care of everything. Will call
44 * Array::AllocFromCode(type_idx, method, count);
45 * Note: AllocFromCode will handle checks for errNegativeArraySize.
46 */
buzbeeed3e9302011-09-23 17:34:19 -070047STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -070048 RegLocation rlSrc)
49{
buzbeedfd3d702011-08-28 12:56:51 -070050 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -070051 uint32_t type_idx = mir->dalvikInsn.vC;
Ian Rogersa3760aa2011-11-14 14:32:37 -080052 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
53 cUnit->dex_cache,
54 *cUnit->dex_file,
55 type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -070056 loadWordDisp(cUnit, rSELF,
57 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
58 } else {
59 UNIMPLEMENTED(WARNING) << "Need to check access of '"
Ian Rogersa3760aa2011-11-14 14:32:37 -080060 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
Ian Rogers28ad40d2011-10-27 15:19:26 -070061 << "' to unresolved type " << type_idx;
62 loadWordDisp(cUnit, rSELF,
63 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
64 }
buzbeedfd3d702011-08-28 12:56:51 -070065 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -070066 loadConstant(cUnit, r0, type_idx); // arg0 <- type_id
buzbeedfd3d702011-08-28 12:56:51 -070067 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070068 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070069 RegLocation rlResult = oatGetReturn(cUnit);
70 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070071}
72
73/*
74 * Similar to genNewArray, but with post-allocation initialization.
75 * Verifier guarantees we're dealing with an array class. Current
76 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
77 * Current code also throws internal unimp if not 'L', '[' or 'I'.
78 */
buzbeeed3e9302011-09-23 17:34:19 -070079STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070080{
81 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070082 int elems = dInsn->vA;
83 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070084 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070085 loadWordDisp(cUnit, rSELF,
Elliott Hughesb408de72011-10-04 14:35:05 -070086 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
Ian Rogersa3760aa2011-11-14 14:32:37 -080087 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
88 cUnit->dex_cache,
89 *cUnit->dex_file,
90 typeId)) {
91 UNIMPLEMENTED(WARNING) << "Need to check access of '"
92 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
93 << "' to unresolved type " << typeId;
Ian Rogers28ad40d2011-10-27 15:19:26 -070094 }
buzbeedfd3d702011-08-28 12:56:51 -070095 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
96 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
97 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070098 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070099 /*
buzbeedfd3d702011-08-28 12:56:51 -0700100 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
101 * return region. Because AllocFromCode placed the new array
102 * in r0, we'll just lock it into place. When debugger support is
103 * added, it may be necessary to additionally copy all return
104 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -0700105 */
buzbee67bf8852011-08-17 17:51:35 -0700106 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -0700107
buzbee67bf8852011-08-17 17:51:35 -0700108 // Having a range of 0 is legal
109 if (isRange && (dInsn->vA > 0)) {
110 /*
111 * Bit of ugliness here. We're going generate a mem copy loop
112 * on the register range, but it is possible that some regs
113 * in the range have been promoted. This is unlikely, but
114 * before generating the copy, we'll just force a flush
115 * of any regs in the source range that have been promoted to
116 * home location.
117 */
118 for (unsigned int i = 0; i < dInsn->vA; i++) {
119 RegLocation loc = oatUpdateLoc(cUnit,
120 oatGetSrc(cUnit, mir, i));
121 if (loc.location == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -0700122 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
123 loc.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700124 }
125 }
126 /*
127 * TUNING note: generated code here could be much improved, but
128 * this is an uncommon operation and isn't especially performance
129 * critical.
130 */
131 int rSrc = oatAllocTemp(cUnit);
132 int rDst = oatAllocTemp(cUnit);
133 int rIdx = oatAllocTemp(cUnit);
134 int rVal = rLR; // Using a lot of temps, rLR is known free here
135 // Set up source pointer
136 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
buzbee67bc2362011-10-11 18:08:40 -0700137 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
138 oatSRegOffset(cUnit, rlFirst.sRegLow));
buzbee67bf8852011-08-17 17:51:35 -0700139 // Set up the target pointer
140 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700141 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700142 // Set up the loop counter (known to be > 0)
buzbee31813452011-10-16 14:33:08 -0700143 loadConstant(cUnit, rIdx, dInsn->vA - 1);
buzbee67bf8852011-08-17 17:51:35 -0700144 // Generate the copy loop. Going backwards for convenience
145 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
146 target->defMask = ENCODE_ALL;
147 // Copy next element
148 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
149 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
150 // Use setflags encoding here
151 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee31813452011-10-16 14:33:08 -0700152 ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
buzbee67bf8852011-08-17 17:51:35 -0700153 branch->generic.target = (LIR*)target;
154 } else if (!isRange) {
155 // TUNING: interleave
156 for (unsigned int i = 0; i < dInsn->vA; i++) {
157 RegLocation rlArg = loadValue(cUnit,
158 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700159 storeBaseDisp(cUnit, r0,
160 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700161 i * 4, rlArg.lowReg, kWord);
162 // If the loadValue caused a temp to be allocated, free it
163 if (oatIsTemp(cUnit, rlArg.lowReg)) {
164 oatFreeTemp(cUnit, rlArg.lowReg);
165 }
166 }
167 }
168}
169
Ian Rogersa3760aa2011-11-14 14:32:37 -0800170Field* FindFieldWithResolvedStaticStorage(CompilationUnit* cUnit,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700171 const uint32_t fieldIdx,
172 uint32_t& resolvedTypeIdx) {
Ian Rogersa3760aa2011-11-14 14:32:37 -0800173 Field* field = cUnit->class_linker->ResolveField(*cUnit->dex_file,
174 fieldIdx,
175 cUnit->dex_cache,
176 cUnit->class_loader,
177 true);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700178 if (field == NULL) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700179 Thread* thread = Thread::Current();
180 if (thread->IsExceptionPending()) { // clear any exception left by resolve field
181 thread->ClearException();
182 }
Brian Carlstrom845490b2011-09-19 15:56:53 -0700183 return NULL;
184 }
Ian Rogersa3760aa2011-11-14 14:32:37 -0800185 const art::DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700186 int type_idx = field_id.class_idx_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800187 Class* klass = cUnit->dex_cache->GetResolvedTypes()->Get(type_idx);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700188 // Check if storage class is the same as class referred to by type idx.
189 // They may not be if the FieldId refers a subclass, but storage is in super
190 if (field->GetDeclaringClass() == klass) {
191 resolvedTypeIdx = type_idx;
192 return field;
193 }
194 // See if we can find a dex reference for the storage class.
195 // we may not if the dex file never references the super class,
196 // but usually it will.
Ian Rogers6d4d9fc2011-11-30 16:24:48 -0800197 std::string descriptor(art::FieldHelper(field).GetDeclaringClassDescriptor());
Ian Rogersa3760aa2011-11-14 14:32:37 -0800198 const art::DexFile::StringId* string_id =
199 cUnit->dex_file->FindStringId(descriptor);
200 if (string_id == NULL) {
201 return NULL; // descriptor not found, resort to slow path
Brian Carlstrom845490b2011-09-19 15:56:53 -0700202 }
Ian Rogersa3760aa2011-11-14 14:32:37 -0800203 const art::DexFile::TypeId* type_id =
204 cUnit->dex_file->FindTypeId(cUnit->dex_file->GetIndexForStringId(*string_id));
205 if (type_id == NULL) {
206 return NULL; // type id not found, resort to slow path
207 }
208 resolvedTypeIdx = cUnit->dex_file->GetIndexForTypeId(*type_id);
209 return field;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700210}
211
buzbeeed3e9302011-09-23 17:34:19 -0700212STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700213{
buzbeee1931742011-08-28 21:15:53 -0700214 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
215 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700216 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700217 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800218 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700219 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700220 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700221 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700222 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700223 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
224 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700225 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
226 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
227 loadCurrMethodDirect(cUnit, r1);
228 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700229 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700230 } else {
buzbee1da522d2011-09-04 11:22:20 -0700231 // fast path
232 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700233 // Using fixed register to sync with slow path
234 int rMethod = r1;
235 oatLockTemp(cUnit, rMethod);
236 loadCurrMethodDirect(cUnit, rMethod);
237 int rBase = r0;
238 oatLockTemp(cUnit, rBase);
239 loadWordDisp(cUnit, rMethod,
240 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
241 rBase);
242 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
243 sizeof(int32_t*)* typeIdx, rBase);
244 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700245 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700246 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
247 loadWordDisp(cUnit, rSELF,
248 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
249 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700250 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700251 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
252 skipTarget->defMask = ENCODE_ALL;
253 branchOver->generic.target = (LIR*)skipTarget;
254 rlSrc = oatGetSrc(cUnit, mir, 0);
255 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700256#if ANDROID_SMP != 0
257 if (field->IsVolatile()) {
258 oatGenMemBarrier(cUnit, kST);
259 }
260#endif
buzbee1da522d2011-09-04 11:22:20 -0700261 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700262#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700263 if (field->IsVolatile()) {
264 oatGenMemBarrier(cUnit, kSY);
265 }
buzbee67bf8852011-08-17 17:51:35 -0700266#endif
buzbee1da522d2011-09-04 11:22:20 -0700267 if (isObject) {
268 markGCCard(cUnit, rlSrc.lowReg, rBase);
269 }
270 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700271 }
buzbee67bf8852011-08-17 17:51:35 -0700272}
273
buzbeeed3e9302011-09-23 17:34:19 -0700274STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700275{
buzbee1da522d2011-09-04 11:22:20 -0700276 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700277 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800278 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700279 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700280#if ANDROID_SMP != 0
281 bool isVolatile = (field == NULL) || field->IsVolatile();
282#else
283 bool isVolatile = false;
284#endif
285 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700286 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700287 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700288 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
289 loadCurrMethodDirect(cUnit, r1);
290 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700291 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700292 } else {
buzbee1da522d2011-09-04 11:22:20 -0700293 // fast path
294 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700295 // Using fixed register to sync with slow path
296 int rMethod = r1;
297 oatLockTemp(cUnit, rMethod);
298 loadCurrMethodDirect(cUnit, r1);
299 int rBase = r0;
300 oatLockTemp(cUnit, rBase);
301 loadWordDisp(cUnit, rMethod,
302 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
303 rBase);
304 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
305 sizeof(int32_t*)* typeIdx, rBase);
306 // TUNING: fast path should fall through
307 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
308 loadWordDisp(cUnit, rSELF,
309 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
310 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700311 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700312 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
313 skipTarget->defMask = ENCODE_ALL;
314 branchOver->generic.target = (LIR*)skipTarget;
315 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
316 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
317 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
318 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700319 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700320 }
buzbee67bf8852011-08-17 17:51:35 -0700321}
322
323
buzbeeed3e9302011-09-23 17:34:19 -0700324STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700325 RegLocation rlResult, RegLocation rlDest)
326{
buzbee1da522d2011-09-04 11:22:20 -0700327 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700328 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800329 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700330#if ANDROID_SMP != 0
331 bool isVolatile = (field == NULL) || field->IsVolatile();
332#else
333 bool isVolatile = false;
334#endif
buzbee6181f792011-09-29 11:14:04 -0700335 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700336 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700337 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700338 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700339 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
340 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700341 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700342 RegLocation rlResult = oatGetReturnWide(cUnit);
343 storeValueWide(cUnit, rlDest, rlResult);
344 } else {
buzbee1da522d2011-09-04 11:22:20 -0700345 // Fast path
346 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700347 // Using fixed register to sync with slow path
348 int rMethod = r1;
349 oatLockTemp(cUnit, rMethod);
350 loadCurrMethodDirect(cUnit, rMethod);
351 int rBase = r0;
352 oatLockTemp(cUnit, rBase);
353 loadWordDisp(cUnit, rMethod,
354 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
355 rBase);
356 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
357 sizeof(int32_t*)* typeIdx, rBase);
358 // TUNING: fast path should fall through
359 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
360 loadWordDisp(cUnit, rSELF,
361 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
362 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700363 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700364 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
365 skipTarget->defMask = ENCODE_ALL;
366 branchOver->generic.target = (LIR*)skipTarget;
367 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
368 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700369 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
370 rlResult.highReg, INVALID_SREG);
371 oatFreeTemp(cUnit, rBase);
372 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700373 }
buzbee67bf8852011-08-17 17:51:35 -0700374}
375
buzbeeed3e9302011-09-23 17:34:19 -0700376STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700377 RegLocation rlResult, RegLocation rlDest)
378{
buzbee1da522d2011-09-04 11:22:20 -0700379 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700380 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800381 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700382 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
383 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700384 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700385 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700386 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700387 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700388 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
389 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700390 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
391 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
392 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700393 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700394 RegLocation rlResult = oatGetReturn(cUnit);
395 storeValue(cUnit, rlDest, rlResult);
396 } else {
buzbee1da522d2011-09-04 11:22:20 -0700397 // Fast path
398 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700399 // Using fixed register to sync with slow path
400 int rMethod = r1;
401 oatLockTemp(cUnit, rMethod);
402 loadCurrMethodDirect(cUnit, rMethod);
403 int rBase = r0;
404 oatLockTemp(cUnit, rBase);
405 loadWordDisp(cUnit, rMethod,
406 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
407 rBase);
408 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
409 sizeof(int32_t*)* typeIdx, rBase);
410 // TUNING: fast path should fall through
411 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
412 loadWordDisp(cUnit, rSELF,
413 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
414 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700415 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700416 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
417 skipTarget->defMask = ENCODE_ALL;
418 branchOver->generic.target = (LIR*)skipTarget;
419 rlDest = oatGetDest(cUnit, mir, 0);
420 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700421#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700422 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700423 oatGenMemBarrier(cUnit, kSY);
424 }
buzbee67bf8852011-08-17 17:51:35 -0700425#endif
buzbee1da522d2011-09-04 11:22:20 -0700426 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
427 oatFreeTemp(cUnit, rBase);
428 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700429 }
buzbee67bf8852011-08-17 17:51:35 -0700430}
431
buzbee561227c2011-09-02 15:28:19 -0700432typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
433 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700434
435/*
436 * Bit of a hack here - in leiu of a real scheduling pass,
437 * emit the next instruction in static & direct invoke sequences.
438 */
buzbeeed3e9302011-09-23 17:34:19 -0700439STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700440 DecodedInstruction* dInsn, int state,
441 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700442{
buzbee561227c2011-09-02 15:28:19 -0700443 DCHECK(rollback == NULL);
444 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700445 switch(state) {
446 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700447 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700448 break;
buzbee561227c2011-09-02 15:28:19 -0700449 case 1: // Get method->code_and_direct_methods_
450 loadWordDisp(cUnit, r0,
451 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
452 r0);
buzbee67bf8852011-08-17 17:51:35 -0700453 break;
buzbee561227c2011-09-02 15:28:19 -0700454 case 2: // Grab target method* and target code_
455 loadWordDisp(cUnit, r0,
456 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
457 loadWordDisp(cUnit, r0,
458 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700459 break;
460 default:
461 return -1;
462 }
463 return state + 1;
464}
465
buzbee67bf8852011-08-17 17:51:35 -0700466/*
467 * Bit of a hack here - in leiu of a real scheduling pass,
468 * emit the next instruction in a virtual invoke sequence.
469 * We can use rLR as a temp prior to target address loading
470 * Note also that we'll load the first argument ("this") into
471 * r1 here rather than the standard loadArgRegs.
472 */
buzbeeed3e9302011-09-23 17:34:19 -0700473STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700474 DecodedInstruction* dInsn, int state,
475 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700476{
buzbee561227c2011-09-02 15:28:19 -0700477 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700478 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700479 /*
480 * This is the fast path in which the target virtual method is
481 * fully resolved at compile time.
482 */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800483 Method* baseMethod = cUnit->class_linker->ResolveMethod(*cUnit->dex_file,
484 dInsn->vB,
485 cUnit->dex_cache,
486 cUnit->class_loader,
487 false);
buzbee561227c2011-09-02 15:28:19 -0700488 CHECK(baseMethod != NULL);
489 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700490 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700491 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700492 rlArg = oatGetSrc(cUnit, mir, 0);
493 loadValueDirectFixed(cUnit, rlArg, r1);
494 break;
buzbee561227c2011-09-02 15:28:19 -0700495 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700496 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700497 // get this->klass_ [use r1, set rLR]
498 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700499 break;
buzbee561227c2011-09-02 15:28:19 -0700500 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
501 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700502 break;
buzbee561227c2011-09-02 15:28:19 -0700503 case 3: // Get target method [use rLR, set r0]
504 loadWordDisp(cUnit, rLR, (target_idx * 4) +
505 art::Array::DataOffset().Int32Value(), r0);
506 break;
507 case 4: // Get the target compiled code address [uses r0, sets rLR]
508 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700509 break;
510 default:
511 return -1;
512 }
513 return state + 1;
514}
515
buzbeeed3e9302011-09-23 17:34:19 -0700516STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700517 DecodedInstruction* dInsn, int state,
518 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700519{
520 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700521 ArmLIR* skipBranch;
522 ArmLIR* skipTarget;
523 /*
524 * This handles the case in which the base method is not fully
525 * resolved at compile time. We must generate code to test
526 * for resolution a run time, bail to the slow path if not to
527 * fill in all the tables. In the latter case, we'll restart at
528 * at the beginning of the sequence.
529 */
buzbee7b1b86d2011-08-26 18:59:10 -0700530 switch(state) {
531 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700532 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700533 break;
buzbee561227c2011-09-02 15:28:19 -0700534 case 1: // Get method->dex_cache_resolved_methods_
535 loadWordDisp(cUnit, r0,
536 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700537 break;
buzbee561227c2011-09-02 15:28:19 -0700538 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
539 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
540 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700541 break;
buzbee561227c2011-09-02 15:28:19 -0700542 case 3: // Resolved?
543 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
544 // Slowest path, bail to helper, rollback and retry
545 loadWordDisp(cUnit, rSELF,
546 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
547 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -0800548 loadConstant(cUnit, r2, false);
Ian Rogersff1ed472011-09-20 13:46:24 -0700549 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700550 genUnconditionalBranch(cUnit, rollback);
551 // Resume normal slow path
552 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
553 skipTarget->defMask = ENCODE_ALL;
554 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700555 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700556 loadBaseDisp(cUnit, mir, rLR,
557 Method::GetMethodIndexOffset().Int32Value(), r0,
558 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700559 // Load "this" [set r1]
560 rlArg = oatGetSrc(cUnit, mir, 0);
561 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700562 break;
563 case 4:
564 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700565 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700566 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700567 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700568 break;
buzbee561227c2011-09-02 15:28:19 -0700569 case 5:
570 // get this->klass_->vtable_ [usr rLR, set rLR]
571 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbeeed3e9302011-09-23 17:34:19 -0700572 DCHECK_EQ((art::Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700573 // In load shadow fold vtable_ object header size into method_index_
574 opRegImm(cUnit, kOpAdd, r0,
575 art::Array::DataOffset().Int32Value() / 4);
576 // Get target Method*
577 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
578 break;
579 case 6: // Get the target compiled code address [uses r0, sets rLR]
580 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700581 break;
582 default:
583 return -1;
584 }
585 return state + 1;
586}
587
buzbeeed3e9302011-09-23 17:34:19 -0700588STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700589 DecodedInstruction* dInsn, int callState,
590 NextCallInsn nextCallInsn, ArmLIR* rollback,
591 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700592{
buzbeec0ecd652011-09-25 18:11:54 -0700593 int nextReg = r1;
594 int nextArg = 0;
595 if (skipThis) {
596 nextReg++;
597 nextArg++;
598 }
599 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
600 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
601 rlArg = oatUpdateRawLoc(cUnit, rlArg);
602 if (rlArg.wide && (nextReg <= r2)) {
603 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
604 nextReg++;
605 nextArg++;
606 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700607 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700608 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700609 }
buzbeec0ecd652011-09-25 18:11:54 -0700610 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700611 }
612 return callState;
613}
614
buzbee4a3164f2011-09-03 11:25:10 -0700615// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700616STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700617 DecodedInstruction* dInsn, int state,
618 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700619{
buzbee510c6052011-10-27 10:47:20 -0700620 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700621 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700622 case 0: // Load trampoline target
623 loadWordDisp(cUnit, rSELF,
624 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
625 rLR);
626 // Load r0 with method index
627 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700628 break;
buzbee67bf8852011-08-17 17:51:35 -0700629 default:
630 return -1;
631 }
632 return state + 1;
633}
634
buzbee67bf8852011-08-17 17:51:35 -0700635/*
636 * Interleave launch code for INVOKE_SUPER. See comments
637 * for nextVCallIns.
638 */
buzbeeed3e9302011-09-23 17:34:19 -0700639STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700640 DecodedInstruction* dInsn, int state,
641 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700642{
buzbee4a3164f2011-09-03 11:25:10 -0700643 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700644 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700645 /*
646 * This is the fast path in which the target virtual method is
647 * fully resolved at compile time. Note also that this path assumes
648 * that the check to verify that the target method index falls
649 * within the size of the super's vtable has been done at compile-time.
650 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700651 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -0800652 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
653 dInsn->vB,
654 cUnit->dex_cache,
655 cUnit->class_loader,
656 false);
buzbee4a3164f2011-09-03 11:25:10 -0700657 CHECK(baseMethod != NULL);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800658 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
659 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
660 Class* superClass = (declaring_class != NULL)
661 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -0700662 CHECK(superClass != NULL);
663 int32_t target_idx = baseMethod->GetMethodIndex();
664 CHECK(superClass->GetVTable()->GetLength() > target_idx);
665 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
666 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700667 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700668 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700669 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700670 // Load "this" [set r1]
671 rlArg = oatGetSrc(cUnit, mir, 0);
672 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700673 // Get method->declaring_class_ [use r0, set rLR]
674 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
675 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700676 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700677 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700678 break;
679 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
680 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
681 rLR);
682 break;
683 case 2: // Get ...->super_class_->vtable [u/s rLR]
684 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
685 break;
686 case 3: // Get target method [use rLR, set r0]
687 loadWordDisp(cUnit, rLR, (target_idx * 4) +
688 art::Array::DataOffset().Int32Value(), r0);
689 break;
690 case 4: // Get the target compiled code address [uses r0, sets rLR]
691 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
692 break;
buzbee67bf8852011-08-17 17:51:35 -0700693 default:
694 return -1;
695 }
buzbee4a3164f2011-09-03 11:25:10 -0700696 return state + 1;
697}
698
699/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700700STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700701 DecodedInstruction* dInsn, int state,
702 ArmLIR* rollback)
703{
buzbee4a3164f2011-09-03 11:25:10 -0700704 RegLocation rlArg;
705 ArmLIR* skipBranch;
706 ArmLIR* skipTarget;
707 int tReg;
708 /*
709 * This handles the case in which the base method is not fully
710 * resolved at compile time. We must generate code to test
711 * for resolution a run time, bail to the slow path if not to
712 * fill in all the tables. In the latter case, we'll restart at
713 * at the beginning of the sequence.
714 */
715 switch(state) {
716 case 0: // Get the current Method* [sets r0]
717 loadCurrMethodDirect(cUnit, r0);
718 break;
buzbee34c77ad2012-01-11 13:01:32 -0800719 case 1: // Get method->dex_cache_resolved_methods_ [uses r0, set rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700720 loadWordDisp(cUnit, r0,
721 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
722 break;
723 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
724 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
725 art::Array::DataOffset().Int32Value(), rLR);
726 break;
727 case 3: // Resolved?
728 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
729 // Slowest path, bail to helper, rollback and retry
730 loadWordDisp(cUnit, rSELF,
731 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
732 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -0800733 loadConstant(cUnit, r2, true);
Ian Rogersff1ed472011-09-20 13:46:24 -0700734 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700735 genUnconditionalBranch(cUnit, rollback);
736 // Resume normal slow path
737 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
738 skipTarget->defMask = ENCODE_ALL;
739 skipBranch->generic.target = (LIR*)skipTarget;
740 // Get base_method->method_index [usr rLR, set rLR]
741 loadBaseDisp(cUnit, mir, rLR,
742 Method::GetMethodIndexOffset().Int32Value(), rLR,
743 kUnsignedHalf, INVALID_SREG);
744 // Load "this" [set r1]
745 rlArg = oatGetSrc(cUnit, mir, 0);
746 loadValueDirectFixed(cUnit, rlArg, r1);
747 // Load curMethod->declaring_class_ [uses r0, sets r0]
748 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
749 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700750 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700751 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700752 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700753 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
754 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700755 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700756 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700757 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700758 // Range check, throw NSM on failure
759 tReg = oatAllocTemp(cUnit);
760 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
761 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700762 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
763 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700764 oatFreeTemp(cUnit, tReg);
765 }
buzbee6a0f7f52011-09-05 16:14:20 -0700766 // Adjust vtable_ base past object header
767 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700768 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700769 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700770 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700771 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700772 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
773 break;
774 default:
775 return -1;
776 }
buzbee67bf8852011-08-17 17:51:35 -0700777 return state + 1;
778}
779
780/*
781 * Load up to 5 arguments, the first three of which will be in
782 * r1 .. r3. On entry r0 contains the current method pointer,
783 * and as part of the load sequence, it must be replaced with
784 * the target method pointer. Note, this may also be called
785 * for "range" variants if the number of arguments is 5 or fewer.
786 */
buzbeeed3e9302011-09-23 17:34:19 -0700787STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700788 DecodedInstruction* dInsn, int callState,
789 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700790 NextCallInsn nextCallInsn, ArmLIR* rollback,
791 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700792{
793 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700794
795 /* If no arguments, just return */
796 if (dInsn->vA == 0)
797 return callState;
798
buzbee561227c2011-09-02 15:28:19 -0700799 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700800
buzbeec0ecd652011-09-25 18:11:54 -0700801 DCHECK_LE(dInsn->vA, 5U);
802 if (dInsn->vA > 3) {
803 uint32_t nextUse = 3;
804 //Detect special case of wide arg spanning arg3/arg4
805 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
806 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
807 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
808 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
809 rlUse2.wide) {
810 int reg;
811 // Wide spans, we need the 2nd half of uses[2].
812 rlArg = oatUpdateLocWide(cUnit, rlUse2);
813 if (rlArg.location == kLocPhysReg) {
814 reg = rlArg.highReg;
815 } else {
816 // r2 & r3 can safely be used here
817 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700818 loadWordDisp(cUnit, rSP,
819 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
buzbeec0ecd652011-09-25 18:11:54 -0700820 callState = nextCallInsn(cUnit, mir, dInsn, callState,
821 rollback);
822 }
823 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
824 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
825 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
826 nextUse++;
827 }
828 // Loop through the rest
829 while (nextUse < dInsn->vA) {
830 int lowReg;
831 int highReg;
832 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
833 rlArg = oatUpdateRawLoc(cUnit, rlArg);
834 if (rlArg.location == kLocPhysReg) {
835 lowReg = rlArg.lowReg;
836 highReg = rlArg.highReg;
837 } else {
838 lowReg = r2;
839 highReg = r3;
840 if (rlArg.wide) {
841 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
842 } else {
843 loadValueDirectFixed(cUnit, rlArg, lowReg);
844 }
845 callState = nextCallInsn(cUnit, mir, dInsn, callState,
846 rollback);
847 }
848 int outsOffset = (nextUse + 1) * 4;
849 if (rlArg.wide) {
850 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
851 nextUse += 2;
852 } else {
853 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
854 nextUse++;
855 }
buzbee561227c2011-09-02 15:28:19 -0700856 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700857 }
buzbee67bf8852011-08-17 17:51:35 -0700858 }
859
buzbeec0ecd652011-09-25 18:11:54 -0700860 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
861 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700862
buzbee67bf8852011-08-17 17:51:35 -0700863 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700864 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700865 }
866 return callState;
867}
868
869/*
870 * May have 0+ arguments (also used for jumbo). Note that
871 * source virtual registers may be in physical registers, so may
872 * need to be flushed to home location before copying. This
873 * applies to arg3 and above (see below).
874 *
875 * Two general strategies:
876 * If < 20 arguments
877 * Pass args 3-18 using vldm/vstm block copy
878 * Pass arg0, arg1 & arg2 in r1-r3
879 * If 20+ arguments
880 * Pass args arg19+ using memcpy block copy
881 * Pass arg0, arg1 & arg2 in r1-r3
882 *
883 */
buzbeeed3e9302011-09-23 17:34:19 -0700884STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700885 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700886 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700887 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700888{
889 int firstArg = dInsn->vC;
890 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700891
buzbee67bf8852011-08-17 17:51:35 -0700892 // If we can treat it as non-range (Jumbo ops will use range form)
893 if (numArgs <= 5)
894 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700895 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700896 /*
897 * Make sure range list doesn't span the break between in normal
898 * Dalvik vRegs and the ins.
899 */
buzbee1b4c8592011-08-31 10:43:51 -0700900 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800901 int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee1b4c8592011-08-31 10:43:51 -0700902 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
903 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700904 }
905
906 /*
907 * First load the non-register arguments. Both forms expect all
908 * of the source arguments to be in their home frame location, so
909 * scan the sReg names and flush any that have been promoted to
910 * frame backing storage.
911 */
912 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700913 for (int nextArg = 0; nextArg < numArgs;) {
914 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700915 if (loc.wide) {
916 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700917 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700918 storeBaseDispWide(cUnit, rSP,
919 oatSRegOffset(cUnit, loc.sRegLow),
920 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700921 }
buzbeec0ecd652011-09-25 18:11:54 -0700922 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700923 } else {
924 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700925 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700926 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
927 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700928 }
buzbeec0ecd652011-09-25 18:11:54 -0700929 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700930 }
931 }
932
buzbee67bc2362011-10-11 18:08:40 -0700933 int startOffset = oatSRegOffset(cUnit,
934 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700935 int outsOffset = 4 /* Method* */ + (3 * 4);
936 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700937 // Generate memcpy
938 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
939 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700940 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
941 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700942 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700943 // Restore Method*
944 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700945 } else {
946 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700947 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700948 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700949 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700950 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
951 //TUNING: loosen barrier
952 ld->defMask = ENCODE_ALL;
953 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700954 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700955 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700956 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700957 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
958 setMemRefType(st, false /* isLoad */, kDalvikReg);
959 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700960 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700961 }
962
buzbeec0ecd652011-09-25 18:11:54 -0700963 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
964 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700965
buzbee561227c2011-09-02 15:28:19 -0700966 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee99f27232011-10-05 12:56:36 -0700967 if (pcrLabel) {
968 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
969 }
buzbee67bf8852011-08-17 17:51:35 -0700970 return callState;
971}
972
buzbee2a475e72011-09-07 17:19:17 -0700973// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700974STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700975{
976 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
977 loadWordDisp(cUnit, rSELF,
978 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
979 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
980 target->defMask = -1;
981 branchOver->generic.target = (LIR*)target;
982}
buzbee2a475e72011-09-07 17:19:17 -0700983
buzbeeed3e9302011-09-23 17:34:19 -0700984STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700985 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700986{
987 DecodedInstruction* dInsn = &mir->dalvikInsn;
988 int callState = 0;
989 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700990 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700991 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700992 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700993
buzbee109bd6a2011-09-06 13:58:41 -0700994 // Explicit register usage
995 oatLockCallTemps(cUnit);
996
buzbee99f27232011-10-05 12:56:36 -0700997 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
998 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
999 int idx = mir->dalvikInsn.vB;
Ian Rogersa3760aa2011-11-14 14:32:37 -08001000 Method* target = cUnit->dex_cache->GetResolvedMethods()->Get(idx);
buzbee99f27232011-10-05 12:56:36 -07001001 if (target) {
1002 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
1003 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
1004 loadValueDirectFixed(cUnit, rlArg, r0);
1005 loadWordDisp(cUnit, rSELF,
1006 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
1007 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
1008 opReg(cUnit, kOpBlx, rLR);
1009 oatClobberCalleeSave(cUnit);
1010 return;
1011 }
1012 }
1013 }
1014
buzbee561227c2011-09-02 15:28:19 -07001015 if (range) {
1016 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -07001017 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -07001018 } else {
1019 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -07001020 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -07001021 }
buzbee67bf8852011-08-17 17:51:35 -07001022 // Finish up any of the call sequence not interleaved in arg loading
1023 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001024 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001025 }
buzbeece302932011-10-04 14:32:18 -07001026 if (DISPLAY_MISSING_TARGETS) {
1027 genShowTarget(cUnit);
1028 }
buzbeeec5adf32011-09-11 15:25:43 -07001029 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001030 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001031}
1032
buzbee4a3164f2011-09-03 11:25:10 -07001033/*
1034 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
1035 * which will locate the target and continue on via a tail call.
1036 */
buzbeeed3e9302011-09-23 17:34:19 -07001037STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001038{
1039 DecodedInstruction* dInsn = &mir->dalvikInsn;
1040 int callState = 0;
1041 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -07001042 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001043
1044 // Explicit register usage
1045 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001046 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -07001047 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001048 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
1049 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001050 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -07001051 false);
buzbee67bf8852011-08-17 17:51:35 -07001052 else
1053 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -07001054 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -07001055 // Finish up any of the call sequence not interleaved in arg loading
1056 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001057 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001058 }
buzbeece302932011-10-04 14:32:18 -07001059 if (DISPLAY_MISSING_TARGETS) {
1060 genShowTarget(cUnit);
1061 }
buzbeeec5adf32011-09-11 15:25:43 -07001062 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001063 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001064}
1065
buzbeeed3e9302011-09-23 17:34:19 -07001066STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001067{
1068 DecodedInstruction* dInsn = &mir->dalvikInsn;
1069 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001070 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001071 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001072 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
1073 dInsn->vB,
1074 cUnit->dex_cache,
1075 cUnit->class_loader,
1076 false);
buzbee4a3164f2011-09-03 11:25:10 -07001077 NextCallInsn nextCallInsn;
1078 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001079 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001080
1081 // Explicit register usage
1082 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -08001083
1084 // For testing, force call to artResolveMethodFromCode & ignore result
1085 if (EXERCISE_RESOLVE_METHOD) {
1086 loadCurrMethodDirect(cUnit, r0);
1087 loadWordDisp(cUnit, rSELF,
1088 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
1089 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -08001090 loadConstant(cUnit, r2, true);
buzbee34c77ad2012-01-11 13:01:32 -08001091 callRuntimeHelper(cUnit, rLR);
1092 }
1093
buzbee34cd9e52011-09-08 14:31:52 -07001094 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001095 Thread* thread = Thread::Current();
1096 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1097 thread->ClearException();
1098 }
buzbee4a3164f2011-09-03 11:25:10 -07001099 fastPath = false;
1100 } else {
Ian Rogersa3760aa2011-11-14 14:32:37 -08001101 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
1102 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
1103 Class* superClass = (declaring_class != NULL)
1104 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -07001105 if (superClass == NULL) {
1106 fastPath = false;
1107 } else {
1108 int32_t target_idx = baseMethod->GetMethodIndex();
1109 if (superClass->GetVTable()->GetLength() <= target_idx) {
1110 fastPath = false;
1111 } else {
1112 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1113 }
1114 }
1115 }
1116 if (fastPath) {
1117 nextCallInsn = nextSuperCallInsn;
1118 rollback = NULL;
1119 } else {
1120 nextCallInsn = nextSuperCallInsnSP;
1121 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1122 rollback->defMask = -1;
1123 }
buzbee67bf8852011-08-17 17:51:35 -07001124 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
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) {
buzbee6a0f7f52011-09-05 16:14:20 -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 void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001142{
1143 DecodedInstruction* dInsn = &mir->dalvikInsn;
1144 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001145 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001146 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001147 Method* method = class_linker->ResolveMethod(*cUnit->dex_file,
1148 dInsn->vB,
1149 cUnit->dex_cache,
1150 cUnit->class_loader,
1151 false);
buzbee561227c2011-09-02 15:28:19 -07001152 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001153 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001154 // Explicit register usage
1155 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -08001156
1157 // For testing, force call to artResolveMethodFromCode & ignore result
1158 if (EXERCISE_RESOLVE_METHOD) {
1159 loadCurrMethodDirect(cUnit, r0);
1160 loadWordDisp(cUnit, rSELF,
1161 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
1162 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -08001163 loadConstant(cUnit, r2, false);
buzbee34c77ad2012-01-11 13:01:32 -08001164 callRuntimeHelper(cUnit, rLR);
1165 }
1166
buzbee34cd9e52011-09-08 14:31:52 -07001167 if (SLOW_INVOKE_PATH || method == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001168 Thread* thread = Thread::Current();
1169 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1170 thread->ClearException();
1171 }
buzbee561227c2011-09-02 15:28:19 -07001172 // Slow path
1173 nextCallInsn = nextVCallInsnSP;
1174 // If we need a slow-path callout, we'll restart here
1175 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1176 rollback->defMask = -1;
1177 } else {
1178 // Fast path
1179 nextCallInsn = nextVCallInsn;
1180 rollback = NULL;
1181 }
buzbee67bf8852011-08-17 17:51:35 -07001182 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001183 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001184 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001185 else
buzbeec0ecd652011-09-25 18:11:54 -07001186 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001187 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001188 // Finish up any of the call sequence not interleaved in arg loading
1189 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001190 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001191 }
buzbeece302932011-10-04 14:32:18 -07001192 if (DISPLAY_MISSING_TARGETS) {
1193 genShowTarget(cUnit);
1194 }
buzbeeec5adf32011-09-11 15:25:43 -07001195 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001196 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001197}
1198
buzbeeed3e9302011-09-23 17:34:19 -07001199STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001200 BasicBlock* bb, ArmLIR* labelList)
1201{
1202 bool res = false; // Assume success
1203 RegLocation rlSrc[3];
1204 RegLocation rlDest = badLoc;
1205 RegLocation rlResult = badLoc;
1206 Opcode opcode = mir->dalvikInsn.opcode;
1207
1208 /* Prep Src and Dest locations */
1209 int nextSreg = 0;
1210 int nextLoc = 0;
1211 int attrs = oatDataFlowAttributes[opcode];
1212 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1213 if (attrs & DF_UA) {
1214 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1215 nextSreg++;
1216 } else if (attrs & DF_UA_WIDE) {
1217 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1218 nextSreg + 1);
1219 nextSreg+= 2;
1220 }
1221 if (attrs & DF_UB) {
1222 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1223 nextSreg++;
1224 } else if (attrs & DF_UB_WIDE) {
1225 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1226 nextSreg + 1);
1227 nextSreg+= 2;
1228 }
1229 if (attrs & DF_UC) {
1230 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1231 } else if (attrs & DF_UC_WIDE) {
1232 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1233 nextSreg + 1);
1234 }
1235 if (attrs & DF_DA) {
1236 rlDest = oatGetDest(cUnit, mir, 0);
1237 } else if (attrs & DF_DA_WIDE) {
1238 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1239 }
1240
1241 switch(opcode) {
1242 case OP_NOP:
1243 break;
1244
1245 case OP_MOVE_EXCEPTION:
1246 int exOffset;
1247 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001248 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001249 resetReg = oatAllocTemp(cUnit);
1250 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1251 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1252 loadConstant(cUnit, resetReg, 0);
1253 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1254 storeValue(cUnit, rlDest, rlResult);
1255 break;
1256
1257 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -07001258 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001259 break;
1260
1261 case OP_RETURN:
1262 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -07001263 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001264 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001265 break;
1266
1267 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -07001268 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001269 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001270 break;
1271
1272 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001273 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001274 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001275 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001276 break;
1277
1278 case OP_MOVE_RESULT:
1279 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001280 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001281 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001282 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001283 break;
1284
1285 case OP_MOVE:
1286 case OP_MOVE_OBJECT:
1287 case OP_MOVE_16:
1288 case OP_MOVE_OBJECT_16:
1289 case OP_MOVE_FROM16:
1290 case OP_MOVE_OBJECT_FROM16:
1291 storeValue(cUnit, rlDest, rlSrc[0]);
1292 break;
1293
1294 case OP_MOVE_WIDE:
1295 case OP_MOVE_WIDE_16:
1296 case OP_MOVE_WIDE_FROM16:
1297 storeValueWide(cUnit, rlDest, rlSrc[0]);
1298 break;
1299
1300 case OP_CONST:
1301 case OP_CONST_4:
1302 case OP_CONST_16:
1303 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1304 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1305 storeValue(cUnit, rlDest, rlResult);
1306 break;
1307
1308 case OP_CONST_HIGH16:
1309 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1310 loadConstantNoClobber(cUnit, rlResult.lowReg,
1311 mir->dalvikInsn.vB << 16);
1312 storeValue(cUnit, rlDest, rlResult);
1313 break;
1314
1315 case OP_CONST_WIDE_16:
1316 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001317 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1318 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1319 mir->dalvikInsn.vB,
1320 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001321 storeValueWide(cUnit, rlDest, rlResult);
1322 break;
1323
1324 case OP_CONST_WIDE:
1325 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1326 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001327 mir->dalvikInsn.vB_wide & 0xffffffff,
1328 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001329 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001330 break;
1331
1332 case OP_CONST_WIDE_HIGH16:
1333 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1334 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1335 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001336 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001337 break;
1338
1339 case OP_MONITOR_ENTER:
1340 genMonitorEnter(cUnit, mir, rlSrc[0]);
1341 break;
1342
1343 case OP_MONITOR_EXIT:
1344 genMonitorExit(cUnit, mir, rlSrc[0]);
1345 break;
1346
1347 case OP_CHECK_CAST:
1348 genCheckCast(cUnit, mir, rlSrc[0]);
1349 break;
1350
1351 case OP_INSTANCE_OF:
1352 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1353 break;
1354
1355 case OP_NEW_INSTANCE:
1356 genNewInstance(cUnit, mir, rlDest);
1357 break;
1358
1359 case OP_THROW:
1360 genThrow(cUnit, mir, rlSrc[0]);
1361 break;
1362
buzbee5ade1d22011-09-09 14:44:52 -07001363 case OP_THROW_VERIFICATION_ERROR:
1364 loadWordDisp(cUnit, rSELF,
1365 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1366 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1367 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001368 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001369 break;
1370
buzbee67bf8852011-08-17 17:51:35 -07001371 case OP_ARRAY_LENGTH:
1372 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001373 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001374 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001375 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001376 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1377 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1378 rlResult.lowReg);
1379 storeValue(cUnit, rlDest, rlResult);
1380 break;
1381
1382 case OP_CONST_STRING:
1383 case OP_CONST_STRING_JUMBO:
1384 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1385 break;
1386
1387 case OP_CONST_CLASS:
1388 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1389 break;
1390
1391 case OP_FILL_ARRAY_DATA:
1392 genFillArrayData(cUnit, mir, rlSrc[0]);
1393 break;
1394
1395 case OP_FILLED_NEW_ARRAY:
1396 genFilledNewArray(cUnit, mir, false /* not range */);
1397 break;
1398
1399 case OP_FILLED_NEW_ARRAY_RANGE:
1400 genFilledNewArray(cUnit, mir, true /* range */);
1401 break;
1402
1403 case OP_NEW_ARRAY:
1404 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1405 break;
1406
1407 case OP_GOTO:
1408 case OP_GOTO_16:
1409 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001410 if (bb->taken->startOffset <= mir->offset) {
1411 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001412 }
1413 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1414 break;
1415
1416 case OP_PACKED_SWITCH:
1417 genPackedSwitch(cUnit, mir, rlSrc[0]);
1418 break;
1419
1420 case OP_SPARSE_SWITCH:
1421 genSparseSwitch(cUnit, mir, rlSrc[0]);
1422 break;
1423
1424 case OP_CMPL_FLOAT:
1425 case OP_CMPG_FLOAT:
1426 case OP_CMPL_DOUBLE:
1427 case OP_CMPG_DOUBLE:
1428 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1429 break;
1430
1431 case OP_CMP_LONG:
1432 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1433 break;
1434
1435 case OP_IF_EQ:
1436 case OP_IF_NE:
1437 case OP_IF_LT:
1438 case OP_IF_GE:
1439 case OP_IF_GT:
1440 case OP_IF_LE: {
1441 bool backwardBranch;
1442 ArmConditionCode cond;
1443 backwardBranch = (bb->taken->startOffset <= mir->offset);
1444 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001445 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001446 }
1447 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1448 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1449 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1450 switch(opcode) {
1451 case OP_IF_EQ:
1452 cond = kArmCondEq;
1453 break;
1454 case OP_IF_NE:
1455 cond = kArmCondNe;
1456 break;
1457 case OP_IF_LT:
1458 cond = kArmCondLt;
1459 break;
1460 case OP_IF_GE:
1461 cond = kArmCondGe;
1462 break;
1463 case OP_IF_GT:
1464 cond = kArmCondGt;
1465 break;
1466 case OP_IF_LE:
1467 cond = kArmCondLe;
1468 break;
1469 default:
1470 cond = (ArmConditionCode)0;
1471 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1472 }
1473 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1474 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1475 break;
1476 }
1477
1478 case OP_IF_EQZ:
1479 case OP_IF_NEZ:
1480 case OP_IF_LTZ:
1481 case OP_IF_GEZ:
1482 case OP_IF_GTZ:
1483 case OP_IF_LEZ: {
1484 bool backwardBranch;
1485 ArmConditionCode cond;
1486 backwardBranch = (bb->taken->startOffset <= mir->offset);
1487 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001488 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001489 }
1490 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1491 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1492 switch(opcode) {
1493 case OP_IF_EQZ:
1494 cond = kArmCondEq;
1495 break;
1496 case OP_IF_NEZ:
1497 cond = kArmCondNe;
1498 break;
1499 case OP_IF_LTZ:
1500 cond = kArmCondLt;
1501 break;
1502 case OP_IF_GEZ:
1503 cond = kArmCondGe;
1504 break;
1505 case OP_IF_GTZ:
1506 cond = kArmCondGt;
1507 break;
1508 case OP_IF_LEZ:
1509 cond = kArmCondLe;
1510 break;
1511 default:
1512 cond = (ArmConditionCode)0;
1513 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1514 }
1515 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1516 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1517 break;
1518 }
1519
1520 case OP_AGET_WIDE:
1521 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1522 break;
1523 case OP_AGET:
1524 case OP_AGET_OBJECT:
1525 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1526 break;
1527 case OP_AGET_BOOLEAN:
1528 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1529 rlDest, 0);
1530 break;
1531 case OP_AGET_BYTE:
1532 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1533 break;
1534 case OP_AGET_CHAR:
1535 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1536 rlDest, 1);
1537 break;
1538 case OP_AGET_SHORT:
1539 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1540 break;
1541 case OP_APUT_WIDE:
1542 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1543 break;
1544 case OP_APUT:
1545 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1546 break;
1547 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001548 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001549 break;
1550 case OP_APUT_SHORT:
1551 case OP_APUT_CHAR:
1552 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1553 rlSrc[0], 1);
1554 break;
1555 case OP_APUT_BYTE:
1556 case OP_APUT_BOOLEAN:
1557 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1558 rlSrc[0], 0);
1559 break;
1560
1561 case OP_IGET_WIDE:
1562 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001563 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001564 break;
1565
1566 case OP_IGET:
1567 case OP_IGET_VOLATILE:
1568 case OP_IGET_OBJECT:
1569 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001570 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001571 break;
1572
1573 case OP_IGET_BOOLEAN:
1574 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001575 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001576 break;
1577
1578 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001579 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001580 break;
1581
1582 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001583 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001584 break;
1585
1586 case OP_IPUT_WIDE:
1587 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001588 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001589 break;
1590
1591 case OP_IPUT_OBJECT:
1592 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001593 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001594 break;
1595
1596 case OP_IPUT:
1597 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001598 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001599 break;
1600
1601 case OP_IPUT_BOOLEAN:
1602 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001603 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001604 break;
1605
1606 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001607 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001608 break;
1609
1610 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001611 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001612 break;
1613
1614 case OP_SGET:
1615 case OP_SGET_OBJECT:
1616 case OP_SGET_BOOLEAN:
1617 case OP_SGET_BYTE:
1618 case OP_SGET_CHAR:
1619 case OP_SGET_SHORT:
1620 genSget(cUnit, mir, rlResult, rlDest);
1621 break;
1622
1623 case OP_SGET_WIDE:
1624 genSgetWide(cUnit, mir, rlResult, rlDest);
1625 break;
1626
1627 case OP_SPUT:
1628 case OP_SPUT_OBJECT:
1629 case OP_SPUT_BOOLEAN:
1630 case OP_SPUT_BYTE:
1631 case OP_SPUT_CHAR:
1632 case OP_SPUT_SHORT:
1633 genSput(cUnit, mir, rlSrc[0]);
1634 break;
1635
1636 case OP_SPUT_WIDE:
1637 genSputWide(cUnit, mir, rlSrc[0]);
1638 break;
1639
1640 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001641 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1642 true /*range*/);
1643 break;
buzbee67bf8852011-08-17 17:51:35 -07001644 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001645 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1646 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001647 break;
1648
1649 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001650 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1651 false /*range*/);
1652 break;
buzbee67bf8852011-08-17 17:51:35 -07001653 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001654 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1655 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001656 break;
1657
1658 case OP_INVOKE_VIRTUAL:
1659 case OP_INVOKE_VIRTUAL_RANGE:
1660 genInvokeVirtual(cUnit, mir);
1661 break;
1662
1663 case OP_INVOKE_SUPER:
1664 case OP_INVOKE_SUPER_RANGE:
1665 genInvokeSuper(cUnit, mir);
1666 break;
1667
1668 case OP_INVOKE_INTERFACE:
1669 case OP_INVOKE_INTERFACE_RANGE:
1670 genInvokeInterface(cUnit, mir);
1671 break;
1672
1673 case OP_NEG_INT:
1674 case OP_NOT_INT:
1675 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1676 break;
1677
1678 case OP_NEG_LONG:
1679 case OP_NOT_LONG:
1680 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1681 break;
1682
1683 case OP_NEG_FLOAT:
1684 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1685 break;
1686
1687 case OP_NEG_DOUBLE:
1688 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1689 break;
1690
1691 case OP_INT_TO_LONG:
1692 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1693 if (rlSrc[0].location == kLocPhysReg) {
1694 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1695 } else {
1696 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1697 }
1698 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1699 rlResult.lowReg, 31);
1700 storeValueWide(cUnit, rlDest, rlResult);
1701 break;
1702
1703 case OP_LONG_TO_INT:
1704 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1705 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1706 storeValue(cUnit, rlDest, rlSrc[0]);
1707 break;
1708
1709 case OP_INT_TO_BYTE:
1710 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1711 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1712 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1713 storeValue(cUnit, rlDest, rlResult);
1714 break;
1715
1716 case OP_INT_TO_SHORT:
1717 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1718 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1719 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1720 storeValue(cUnit, rlDest, rlResult);
1721 break;
1722
1723 case OP_INT_TO_CHAR:
1724 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1725 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1726 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1727 storeValue(cUnit, rlDest, rlResult);
1728 break;
1729
1730 case OP_INT_TO_FLOAT:
1731 case OP_INT_TO_DOUBLE:
1732 case OP_LONG_TO_FLOAT:
1733 case OP_LONG_TO_DOUBLE:
1734 case OP_FLOAT_TO_INT:
1735 case OP_FLOAT_TO_LONG:
1736 case OP_FLOAT_TO_DOUBLE:
1737 case OP_DOUBLE_TO_INT:
1738 case OP_DOUBLE_TO_LONG:
1739 case OP_DOUBLE_TO_FLOAT:
1740 genConversion(cUnit, mir);
1741 break;
1742
1743 case OP_ADD_INT:
1744 case OP_SUB_INT:
1745 case OP_MUL_INT:
1746 case OP_DIV_INT:
1747 case OP_REM_INT:
1748 case OP_AND_INT:
1749 case OP_OR_INT:
1750 case OP_XOR_INT:
1751 case OP_SHL_INT:
1752 case OP_SHR_INT:
1753 case OP_USHR_INT:
1754 case OP_ADD_INT_2ADDR:
1755 case OP_SUB_INT_2ADDR:
1756 case OP_MUL_INT_2ADDR:
1757 case OP_DIV_INT_2ADDR:
1758 case OP_REM_INT_2ADDR:
1759 case OP_AND_INT_2ADDR:
1760 case OP_OR_INT_2ADDR:
1761 case OP_XOR_INT_2ADDR:
1762 case OP_SHL_INT_2ADDR:
1763 case OP_SHR_INT_2ADDR:
1764 case OP_USHR_INT_2ADDR:
1765 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1766 break;
1767
1768 case OP_ADD_LONG:
1769 case OP_SUB_LONG:
1770 case OP_MUL_LONG:
1771 case OP_DIV_LONG:
1772 case OP_REM_LONG:
1773 case OP_AND_LONG:
1774 case OP_OR_LONG:
1775 case OP_XOR_LONG:
1776 case OP_ADD_LONG_2ADDR:
1777 case OP_SUB_LONG_2ADDR:
1778 case OP_MUL_LONG_2ADDR:
1779 case OP_DIV_LONG_2ADDR:
1780 case OP_REM_LONG_2ADDR:
1781 case OP_AND_LONG_2ADDR:
1782 case OP_OR_LONG_2ADDR:
1783 case OP_XOR_LONG_2ADDR:
1784 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1785 break;
1786
buzbee67bf8852011-08-17 17:51:35 -07001787 case OP_SHL_LONG:
1788 case OP_SHR_LONG:
1789 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001790 case OP_SHL_LONG_2ADDR:
1791 case OP_SHR_LONG_2ADDR:
1792 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001793 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1794 break;
1795
1796 case OP_ADD_FLOAT:
1797 case OP_SUB_FLOAT:
1798 case OP_MUL_FLOAT:
1799 case OP_DIV_FLOAT:
1800 case OP_REM_FLOAT:
1801 case OP_ADD_FLOAT_2ADDR:
1802 case OP_SUB_FLOAT_2ADDR:
1803 case OP_MUL_FLOAT_2ADDR:
1804 case OP_DIV_FLOAT_2ADDR:
1805 case OP_REM_FLOAT_2ADDR:
1806 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1807 break;
1808
1809 case OP_ADD_DOUBLE:
1810 case OP_SUB_DOUBLE:
1811 case OP_MUL_DOUBLE:
1812 case OP_DIV_DOUBLE:
1813 case OP_REM_DOUBLE:
1814 case OP_ADD_DOUBLE_2ADDR:
1815 case OP_SUB_DOUBLE_2ADDR:
1816 case OP_MUL_DOUBLE_2ADDR:
1817 case OP_DIV_DOUBLE_2ADDR:
1818 case OP_REM_DOUBLE_2ADDR:
1819 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1820 break;
1821
1822 case OP_RSUB_INT:
1823 case OP_ADD_INT_LIT16:
1824 case OP_MUL_INT_LIT16:
1825 case OP_DIV_INT_LIT16:
1826 case OP_REM_INT_LIT16:
1827 case OP_AND_INT_LIT16:
1828 case OP_OR_INT_LIT16:
1829 case OP_XOR_INT_LIT16:
1830 case OP_ADD_INT_LIT8:
1831 case OP_RSUB_INT_LIT8:
1832 case OP_MUL_INT_LIT8:
1833 case OP_DIV_INT_LIT8:
1834 case OP_REM_INT_LIT8:
1835 case OP_AND_INT_LIT8:
1836 case OP_OR_INT_LIT8:
1837 case OP_XOR_INT_LIT8:
1838 case OP_SHL_INT_LIT8:
1839 case OP_SHR_INT_LIT8:
1840 case OP_USHR_INT_LIT8:
1841 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1842 break;
1843
1844 default:
1845 res = true;
1846 }
1847 return res;
1848}
1849
Elliott Hughesc1f143d2011-12-01 17:31:10 -08001850STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001851 "kMirOpPhi",
1852 "kMirOpNullNRangeUpCheck",
1853 "kMirOpNullNRangeDownCheck",
1854 "kMirOpLowerBound",
1855 "kMirOpPunt",
1856 "kMirOpCheckInlinePrediction",
1857};
1858
1859/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001860STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001861{
1862 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1863 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1864 strcpy(msg, extendedMIROpNames[opOffset]);
1865 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1866
1867 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1868 case kMirOpPhi: {
1869 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1870 op->flags.isNop = true;
1871 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1872 break;
1873 }
1874 default:
1875 break;
1876 }
1877}
1878
buzbee67bc2362011-10-11 18:08:40 -07001879/*
1880 * If there are any ins passed in registers that have not been promoted
1881 * to a callee-save register, flush them to the frame. Perform intial
1882 * assignment of promoted arguments.
1883 */
buzbeeed3e9302011-09-23 17:34:19 -07001884STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001885{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001886 if (cUnit->numIns == 0)
buzbee67bf8852011-08-17 17:51:35 -07001887 return;
buzbee67bc2362011-10-11 18:08:40 -07001888 int firstArgReg = r1;
1889 int lastArgReg = r3;
Ian Rogersa3760aa2011-11-14 14:32:37 -08001890 int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee8febc582011-10-25 12:39:20 -07001891 /*
1892 * Arguments passed in registers should be flushed
1893 * to their backing locations in the frame for now.
1894 * Also, we need to do initial assignment for promoted
1895 * arguments. NOTE: an older version of dx had an issue
1896 * in which it would reuse static method argument registers.
1897 * This could result in the same Dalvik virtual register
1898 * being promoted to both core and fp regs. In those
1899 * cases, copy argument to both. This will be uncommon
1900 * enough that it isn't worth attempting to optimize.
1901 */
Ian Rogersa3760aa2011-11-14 14:32:37 -08001902 for (int i = 0; i < cUnit->numIns; i++) {
buzbee67bc2362011-10-11 18:08:40 -07001903 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001904 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001905 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001906 if (vMap.coreLocation == kLocPhysReg) {
1907 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001908 }
1909 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001910 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1911 }
1912 // Also put a copy in memory in case we're partially promoted
1913 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1914 firstArgReg + i, kWord);
1915 } else {
buzbee8febc582011-10-25 12:39:20 -07001916 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001917 if (vMap.coreLocation == kLocPhysReg) {
1918 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1919 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001920 }
1921 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001922 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1923 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001924 }
1925 }
buzbee67bf8852011-08-17 17:51:35 -07001926 }
1927}
1928
1929/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001930STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001931{
1932 MIR* mir;
1933 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1934 int blockId = bb->id;
1935
1936 cUnit->curBlock = bb;
1937 labelList[blockId].operands[0] = bb->startOffset;
1938
1939 /* Insert the block label */
1940 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1941 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1942
buzbee6181f792011-09-29 11:14:04 -07001943 /* Reset local optimization data on block boundaries */
1944 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001945 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001946 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001947
1948 ArmLIR* headLIR = NULL;
1949
buzbeebbaf8942011-10-02 13:08:29 -07001950 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001951 if (bb->blockType == kEntryBlock) {
1952 /*
1953 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1954 * mechanism know so it doesn't try to use any of them when
1955 * expanding the frame or flushing. This leaves the utility
1956 * code with a single temp: r12. This should be enough.
1957 */
1958 oatLockTemp(cUnit, r0);
1959 oatLockTemp(cUnit, r1);
1960 oatLockTemp(cUnit, r2);
1961 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001962
1963 /*
1964 * We can safely skip the stack overflow check if we're
1965 * a leaf *and* our frame size < fudge factor.
1966 */
1967 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1968 ((size_t)cUnit->frameSize <
1969 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001970 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001971 if (!skipOverflowCheck) {
1972 /* Load stack limit */
1973 loadWordDisp(cUnit, rSELF,
1974 art::Thread::StackEndOffset().Int32Value(), r12);
1975 }
buzbee67bf8852011-08-17 17:51:35 -07001976 /* Spill core callee saves */
1977 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1978 /* Need to spill any FP regs? */
1979 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001980 /*
1981 * NOTE: fp spills are a little different from core spills in that
1982 * they are pushed as a contiguous block. When promoting from
1983 * the fp set, we must allocate all singles from s16..highest-promoted
1984 */
buzbee67bf8852011-08-17 17:51:35 -07001985 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1986 }
buzbeecefd1872011-09-09 09:59:52 -07001987 if (!skipOverflowCheck) {
1988 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001989 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001990 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1991 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001992 genRegCopy(cUnit, rSP, rLR); // Establish stack
1993 } else {
1994 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001995 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001996 }
buzbee67bf8852011-08-17 17:51:35 -07001997 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1998 flushIns(cUnit);
1999 oatFreeTemp(cUnit, r0);
2000 oatFreeTemp(cUnit, r1);
2001 oatFreeTemp(cUnit, r2);
2002 oatFreeTemp(cUnit, r3);
2003 } else if (bb->blockType == kExitBlock) {
2004 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07002005 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07002006 /* Need to restore any FP callee saves? */
2007 if (cUnit->numFPSpills) {
2008 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
2009 }
2010 if (cUnit->coreSpillMask & (1 << rLR)) {
2011 /* Unspill rLR to rPC */
2012 cUnit->coreSpillMask &= ~(1 << rLR);
2013 cUnit->coreSpillMask |= (1 << rPC);
2014 }
2015 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
2016 if (!(cUnit->coreSpillMask & (1 << rPC))) {
2017 /* We didn't pop to rPC, so must do a bv rLR */
2018 newLIR1(cUnit, kThumbBx, rLR);
2019 }
2020 }
2021
2022 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
2023
2024 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07002025 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
2026 oatClobberAllRegs(cUnit);
2027 }
buzbee67bf8852011-08-17 17:51:35 -07002028
2029 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
2030 oatResetDefTracking(cUnit);
2031 }
2032
2033 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
2034 handleExtendedMethodMIR(cUnit, mir);
2035 continue;
2036 }
2037
2038 cUnit->currentDalvikOffset = mir->offset;
2039
2040 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2041 InstructionFormat dalvikFormat =
2042 dexGetFormatFromOpcode(dalvikOpcode);
2043
2044 ArmLIR* boundaryLIR;
2045
2046 /* Mark the beginning of a Dalvik instruction for line tracking */
2047 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
2048 (int) oatGetDalvikDisassembly(
2049 &mir->dalvikInsn, ""));
2050 /* Remember the first LIR for this block */
2051 if (headLIR == NULL) {
2052 headLIR = boundaryLIR;
2053 /* Set the first boundaryLIR as a scheduling barrier */
2054 headLIR->defMask = ENCODE_ALL;
2055 }
2056
2057 /* Don't generate the SSA annotation unless verbose mode is on */
2058 if (cUnit->printMe && mir->ssaRep) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -08002059 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
buzbee67bf8852011-08-17 17:51:35 -07002060 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
2061 }
2062
2063 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
2064
2065 if (notHandled) {
2066 char buf[100];
2067 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
2068 mir->offset,
2069 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
2070 dalvikFormat);
2071 LOG(FATAL) << buf;
2072 }
2073 }
2074
2075 if (headLIR) {
2076 /*
2077 * Eliminate redundant loads/stores and delay stores into later
2078 * slots
2079 */
2080 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
2081 cUnit->lastLIRInsn);
2082
2083 /*
2084 * Generate an unconditional branch to the fallthrough block.
2085 */
2086 if (bb->fallThrough) {
2087 genUnconditionalBranch(cUnit,
2088 &labelList[bb->fallThrough->id]);
2089 }
2090 }
2091 return false;
2092}
2093
2094/*
2095 * Nop any unconditional branches that go to the next instruction.
2096 * Note: new redundant branches may be inserted later, and we'll
2097 * use a check in final instruction assembly to nop those out.
2098 */
2099void removeRedundantBranches(CompilationUnit* cUnit)
2100{
2101 ArmLIR* thisLIR;
2102
2103 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2104 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2105 thisLIR = NEXT_LIR(thisLIR)) {
2106
2107 /* Branch to the next instruction */
2108 if ((thisLIR->opcode == kThumbBUncond) ||
2109 (thisLIR->opcode == kThumb2BUncond)) {
2110 ArmLIR* nextLIR = thisLIR;
2111
2112 while (true) {
2113 nextLIR = NEXT_LIR(nextLIR);
2114
2115 /*
2116 * Is the branch target the next instruction?
2117 */
2118 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2119 thisLIR->flags.isNop = true;
2120 break;
2121 }
2122
2123 /*
2124 * Found real useful stuff between the branch and the target.
2125 * Need to explicitly check the lastLIRInsn here because it
2126 * might be the last real instruction.
2127 */
2128 if (!isPseudoOpcode(nextLIR->opcode) ||
2129 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2130 break;
2131 }
2132 }
2133 }
2134}
2135
buzbeeed3e9302011-09-23 17:34:19 -07002136STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002137{
2138 ArmLIR** suspendLabel =
2139 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2140 int numElems = cUnit->suspendLaunchpads.numUsed;
2141
2142 for (int i = 0; i < numElems; i++) {
2143 /* TUNING: move suspend count load into helper */
2144 ArmLIR* lab = suspendLabel[i];
2145 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2146 cUnit->currentDalvikOffset = lab->operands[1];
2147 oatAppendLIR(cUnit, (LIR *)lab);
2148 loadWordDisp(cUnit, rSELF,
2149 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2150 loadWordDisp(cUnit, rSELF,
2151 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2152 opReg(cUnit, kOpBlx, rLR);
2153 genUnconditionalBranch(cUnit, resumeLab);
2154 }
2155}
2156
buzbeeed3e9302011-09-23 17:34:19 -07002157STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002158{
2159 ArmLIR** throwLabel =
2160 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2161 int numElems = cUnit->throwLaunchpads.numUsed;
2162 int i;
2163
2164 for (i = 0; i < numElems; i++) {
2165 ArmLIR* lab = throwLabel[i];
2166 cUnit->currentDalvikOffset = lab->operands[1];
2167 oatAppendLIR(cUnit, (LIR *)lab);
2168 int funcOffset = 0;
2169 int v1 = lab->operands[2];
2170 int v2 = lab->operands[3];
2171 switch(lab->operands[0]) {
2172 case kArmThrowNullPointer:
2173 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2174 break;
2175 case kArmThrowArrayBounds:
2176 if (v2 != r0) {
2177 genRegCopy(cUnit, r0, v1);
2178 genRegCopy(cUnit, r1, v2);
2179 } else {
2180 if (v1 == r1) {
2181 genRegCopy(cUnit, r12, v1);
2182 genRegCopy(cUnit, r1, v2);
2183 genRegCopy(cUnit, r0, r12);
2184 } else {
2185 genRegCopy(cUnit, r1, v2);
2186 genRegCopy(cUnit, r0, v1);
2187 }
2188 }
2189 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2190 break;
2191 case kArmThrowDivZero:
2192 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2193 break;
2194 case kArmThrowVerificationError:
2195 loadConstant(cUnit, r0, v1);
2196 loadConstant(cUnit, r1, v2);
2197 funcOffset =
2198 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2199 break;
2200 case kArmThrowNegArraySize:
2201 genRegCopy(cUnit, r0, v1);
2202 funcOffset =
2203 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2204 break;
buzbee5ade1d22011-09-09 14:44:52 -07002205 case kArmThrowNoSuchMethod:
buzbee95f08792012-01-11 10:51:30 -08002206 genRegCopy(cUnit, r0, v2);
buzbee5ade1d22011-09-09 14:44:52 -07002207 funcOffset =
2208 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2209 break;
buzbeeec5adf32011-09-11 15:25:43 -07002210 case kArmThrowStackOverflow:
2211 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002212 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002213 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002214 opRegImm(cUnit, kOpAdd, rSP,
2215 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002216 break;
buzbee5ade1d22011-09-09 14:44:52 -07002217 default:
2218 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2219 }
2220 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002221 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002222 }
2223}
2224
buzbee67bf8852011-08-17 17:51:35 -07002225void oatMethodMIR2LIR(CompilationUnit* cUnit)
2226{
2227 /* Used to hold the labels of each block */
2228 cUnit->blockLabelList =
2229 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2230
2231 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2232 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002233 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002234
2235 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002236
2237 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002238}
2239
2240/* Common initialization routine for an architecture family */
2241bool oatArchInit()
2242{
2243 int i;
2244
2245 for (i = 0; i < kArmLast; i++) {
2246 if (EncodingMap[i].opcode != i) {
2247 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2248 " is wrong: expecting " << i << ", seeing " <<
2249 (int)EncodingMap[i].opcode;
2250 }
2251 }
2252
2253 return oatArchVariantInit();
2254}
2255
2256/* Needed by the Assembler */
2257void oatSetupResourceMasks(ArmLIR* lir)
2258{
2259 setupResourceMasks(lir);
2260}
2261
2262/* Needed by the ld/st optmizatons */
2263ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2264{
2265 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2266}
2267
2268/* Needed by the register allocator */
2269ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2270{
2271 return genRegCopy(cUnit, rDest, rSrc);
2272}
2273
2274/* Needed by the register allocator */
2275void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2276 int srcLo, int srcHi)
2277{
2278 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2279}
2280
2281void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2282 int displacement, int rSrc, OpSize size)
2283{
2284 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2285}
2286
2287void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2288 int displacement, int rSrcLo, int rSrcHi)
2289{
2290 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2291}