blob: 77b58ff344ec454768205e2ce779aa8d209738a3 [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
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080019namespace art {
20
buzbeece302932011-10-04 14:32:18 -070021#define DISPLAY_MISSING_TARGETS (cUnit->enableDebug & \
22 (1 << kDebugDisplayMissingTargets))
Elliott Hughes1240dad2011-09-09 16:24:50 -070023
buzbee67bc2362011-10-11 18:08:40 -070024STATIC const RegLocation badLoc = {kLocDalvikFrame, 0, 0, 0, 0, 0, 0, INVALID_REG,
25 INVALID_REG, INVALID_SREG};
buzbee6181f792011-09-29 11:14:04 -070026
27/* Mark register usage state and return long retloc */
28STATIC RegLocation getRetLocWide(CompilationUnit* cUnit)
29{
30 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
31 oatLockTemp(cUnit, res.lowReg);
32 oatLockTemp(cUnit, res.highReg);
33 oatMarkPair(cUnit, res.lowReg, res.highReg);
34 return res;
35}
36
37STATIC RegLocation getRetLoc(CompilationUnit* cUnit)
38{
39 RegLocation res = LOC_DALVIK_RETURN_VAL;
40 oatLockTemp(cUnit, res.lowReg);
41 return res;
42}
buzbee67bf8852011-08-17 17:51:35 -070043
buzbeedfd3d702011-08-28 12:56:51 -070044/*
45 * Let helper function take care of everything. Will call
46 * Array::AllocFromCode(type_idx, method, count);
47 * Note: AllocFromCode will handle checks for errNegativeArraySize.
48 */
buzbeeed3e9302011-09-23 17:34:19 -070049STATIC void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
buzbee67bf8852011-08-17 17:51:35 -070050 RegLocation rlSrc)
51{
buzbeedfd3d702011-08-28 12:56:51 -070052 oatFlushAllRegs(cUnit); /* Everything to home location */
Ian Rogers28ad40d2011-10-27 15:19:26 -070053 uint32_t type_idx = mir->dalvikInsn.vC;
Ian Rogersa3760aa2011-11-14 14:32:37 -080054 if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
55 cUnit->dex_cache,
56 *cUnit->dex_file,
57 type_idx)) {
Ian Rogers28ad40d2011-10-27 15:19:26 -070058 loadWordDisp(cUnit, rSELF,
59 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
60 } else {
61 UNIMPLEMENTED(WARNING) << "Need to check access of '"
Ian Rogersa3760aa2011-11-14 14:32:37 -080062 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
Ian Rogers28ad40d2011-10-27 15:19:26 -070063 << "' to unresolved type " << type_idx;
64 loadWordDisp(cUnit, rSELF,
65 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
66 }
buzbeedfd3d702011-08-28 12:56:51 -070067 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
Ian Rogers28ad40d2011-10-27 15:19:26 -070068 loadConstant(cUnit, r0, type_idx); // arg0 <- type_id
buzbeedfd3d702011-08-28 12:56:51 -070069 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070070 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070071 RegLocation rlResult = oatGetReturn(cUnit);
72 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070073}
74
75/*
76 * Similar to genNewArray, but with post-allocation initialization.
77 * Verifier guarantees we're dealing with an array class. Current
78 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
79 * Current code also throws internal unimp if not 'L', '[' or 'I'.
80 */
buzbeeed3e9302011-09-23 17:34:19 -070081STATIC void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
buzbee67bf8852011-08-17 17:51:35 -070082{
83 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070084 int elems = dInsn->vA;
85 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070086 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070087 loadWordDisp(cUnit, rSELF,
Elliott Hughesb408de72011-10-04 14:35:05 -070088 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
Ian Rogersa3760aa2011-11-14 14:32:37 -080089 if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
90 cUnit->dex_cache,
91 *cUnit->dex_file,
92 typeId)) {
93 UNIMPLEMENTED(WARNING) << "Need to check access of '"
94 << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
95 << "' to unresolved type " << typeId;
Ian Rogers28ad40d2011-10-27 15:19:26 -070096 }
buzbeedfd3d702011-08-28 12:56:51 -070097 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
98 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
99 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -0700100 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700101 /*
buzbeedfd3d702011-08-28 12:56:51 -0700102 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
103 * return region. Because AllocFromCode placed the new array
104 * in r0, we'll just lock it into place. When debugger support is
105 * added, it may be necessary to additionally copy all return
106 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -0700107 */
buzbee67bf8852011-08-17 17:51:35 -0700108 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -0700109
buzbee67bf8852011-08-17 17:51:35 -0700110 // Having a range of 0 is legal
111 if (isRange && (dInsn->vA > 0)) {
112 /*
113 * Bit of ugliness here. We're going generate a mem copy loop
114 * on the register range, but it is possible that some regs
115 * in the range have been promoted. This is unlikely, but
116 * before generating the copy, we'll just force a flush
117 * of any regs in the source range that have been promoted to
118 * home location.
119 */
120 for (unsigned int i = 0; i < dInsn->vA; i++) {
121 RegLocation loc = oatUpdateLoc(cUnit,
122 oatGetSrc(cUnit, mir, i));
123 if (loc.location == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -0700124 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
125 loc.lowReg, kWord);
buzbee67bf8852011-08-17 17:51:35 -0700126 }
127 }
128 /*
129 * TUNING note: generated code here could be much improved, but
130 * this is an uncommon operation and isn't especially performance
131 * critical.
132 */
133 int rSrc = oatAllocTemp(cUnit);
134 int rDst = oatAllocTemp(cUnit);
135 int rIdx = oatAllocTemp(cUnit);
136 int rVal = rLR; // Using a lot of temps, rLR is known free here
137 // Set up source pointer
138 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
buzbee67bc2362011-10-11 18:08:40 -0700139 opRegRegImm(cUnit, kOpAdd, rSrc, rSP,
140 oatSRegOffset(cUnit, rlFirst.sRegLow));
buzbee67bf8852011-08-17 17:51:35 -0700141 // Set up the target pointer
142 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700143 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700144 // Set up the loop counter (known to be > 0)
buzbee31813452011-10-16 14:33:08 -0700145 loadConstant(cUnit, rIdx, dInsn->vA - 1);
buzbee67bf8852011-08-17 17:51:35 -0700146 // Generate the copy loop. Going backwards for convenience
147 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
148 target->defMask = ENCODE_ALL;
149 // Copy next element
150 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
151 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
152 // Use setflags encoding here
153 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
buzbee31813452011-10-16 14:33:08 -0700154 ArmLIR* branch = opCondBranch(cUnit, kArmCondGe);
buzbee67bf8852011-08-17 17:51:35 -0700155 branch->generic.target = (LIR*)target;
156 } else if (!isRange) {
157 // TUNING: interleave
158 for (unsigned int i = 0; i < dInsn->vA; i++) {
159 RegLocation rlArg = loadValue(cUnit,
160 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700161 storeBaseDisp(cUnit, r0,
162 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700163 i * 4, rlArg.lowReg, kWord);
164 // If the loadValue caused a temp to be allocated, free it
165 if (oatIsTemp(cUnit, rlArg.lowReg)) {
166 oatFreeTemp(cUnit, rlArg.lowReg);
167 }
168 }
169 }
170}
171
Ian Rogersa3760aa2011-11-14 14:32:37 -0800172Field* FindFieldWithResolvedStaticStorage(CompilationUnit* cUnit,
Brian Carlstrom845490b2011-09-19 15:56:53 -0700173 const uint32_t fieldIdx,
174 uint32_t& resolvedTypeIdx) {
Ian Rogersa3760aa2011-11-14 14:32:37 -0800175 Field* field = cUnit->class_linker->ResolveField(*cUnit->dex_file,
176 fieldIdx,
177 cUnit->dex_cache,
178 cUnit->class_loader,
179 true);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700180 if (field == NULL) {
Ian Rogersb093c6b2011-10-31 16:19:55 -0700181 Thread* thread = Thread::Current();
182 if (thread->IsExceptionPending()) { // clear any exception left by resolve field
183 thread->ClearException();
184 }
Brian Carlstrom845490b2011-09-19 15:56:53 -0700185 return NULL;
186 }
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800187 const DexFile::FieldId& field_id = cUnit->dex_file->GetFieldId(fieldIdx);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700188 int type_idx = field_id.class_idx_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800189 Class* klass = cUnit->dex_cache->GetResolvedTypes()->Get(type_idx);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700190 // Check if storage class is the same as class referred to by type idx.
191 // They may not be if the FieldId refers a subclass, but storage is in super
192 if (field->GetDeclaringClass() == klass) {
193 resolvedTypeIdx = type_idx;
194 return field;
195 }
196 // See if we can find a dex reference for the storage class.
197 // we may not if the dex file never references the super class,
198 // but usually it will.
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800199 std::string descriptor(FieldHelper(field).GetDeclaringClassDescriptor());
200 const DexFile::StringId* string_id =
Ian Rogersa3760aa2011-11-14 14:32:37 -0800201 cUnit->dex_file->FindStringId(descriptor);
202 if (string_id == NULL) {
203 return NULL; // descriptor not found, resort to slow path
Brian Carlstrom845490b2011-09-19 15:56:53 -0700204 }
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800205 const DexFile::TypeId* type_id =
Ian Rogersa3760aa2011-11-14 14:32:37 -0800206 cUnit->dex_file->FindTypeId(cUnit->dex_file->GetIndexForStringId(*string_id));
207 if (type_id == NULL) {
208 return NULL; // type id not found, resort to slow path
209 }
210 resolvedTypeIdx = cUnit->dex_file->GetIndexForTypeId(*type_id);
211 return field;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700212}
213
buzbeeed3e9302011-09-23 17:34:19 -0700214STATIC void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700215{
buzbeee1931742011-08-28 21:15:53 -0700216 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
217 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700218 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700219 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800220 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700221 oatFlushAllRegs(cUnit);
Brian Carlstrom845490b2011-09-19 15:56:53 -0700222 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700223 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700224 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700225 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
226 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700227 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
228 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
229 loadCurrMethodDirect(cUnit, r1);
230 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700231 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700232 } else {
buzbee1da522d2011-09-04 11:22:20 -0700233 // fast path
234 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700235 // Using fixed register to sync with slow path
236 int rMethod = r1;
237 oatLockTemp(cUnit, rMethod);
238 loadCurrMethodDirect(cUnit, rMethod);
239 int rBase = r0;
240 oatLockTemp(cUnit, rBase);
241 loadWordDisp(cUnit, rMethod,
242 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
243 rBase);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800244 loadWordDisp(cUnit, rBase, Array::DataOffset().Int32Value() +
buzbee1da522d2011-09-04 11:22:20 -0700245 sizeof(int32_t*)* typeIdx, rBase);
246 // TUNING: fast path should fall through
buzbeec0ecd652011-09-25 18:11:54 -0700247 // TUNING: Try a conditional skip here, might be faster
buzbee1da522d2011-09-04 11:22:20 -0700248 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
249 loadWordDisp(cUnit, rSELF,
250 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
251 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700252 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700253 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
254 skipTarget->defMask = ENCODE_ALL;
255 branchOver->generic.target = (LIR*)skipTarget;
256 rlSrc = oatGetSrc(cUnit, mir, 0);
257 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
buzbee12246b82011-09-29 14:15:05 -0700258#if ANDROID_SMP != 0
259 if (field->IsVolatile()) {
260 oatGenMemBarrier(cUnit, kST);
261 }
262#endif
buzbee1da522d2011-09-04 11:22:20 -0700263 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700264#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700265 if (field->IsVolatile()) {
266 oatGenMemBarrier(cUnit, kSY);
267 }
buzbee67bf8852011-08-17 17:51:35 -0700268#endif
buzbee1da522d2011-09-04 11:22:20 -0700269 if (isObject) {
270 markGCCard(cUnit, rlSrc.lowReg, rBase);
271 }
272 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700273 }
buzbee67bf8852011-08-17 17:51:35 -0700274}
275
buzbeeed3e9302011-09-23 17:34:19 -0700276STATIC void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
buzbee67bf8852011-08-17 17:51:35 -0700277{
buzbee1da522d2011-09-04 11:22:20 -0700278 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700279 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800280 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee6181f792011-09-29 11:14:04 -0700281 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700282#if ANDROID_SMP != 0
283 bool isVolatile = (field == NULL) || field->IsVolatile();
284#else
285 bool isVolatile = false;
286#endif
287 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700288 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700289 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700290 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
291 loadCurrMethodDirect(cUnit, r1);
292 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700293 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700294 } else {
buzbee1da522d2011-09-04 11:22:20 -0700295 // fast path
296 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700297 // Using fixed register to sync with slow path
298 int rMethod = r1;
299 oatLockTemp(cUnit, rMethod);
300 loadCurrMethodDirect(cUnit, r1);
301 int rBase = r0;
302 oatLockTemp(cUnit, rBase);
303 loadWordDisp(cUnit, rMethod,
304 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
305 rBase);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800306 loadWordDisp(cUnit, rBase, Array::DataOffset().Int32Value() +
buzbee1da522d2011-09-04 11:22:20 -0700307 sizeof(int32_t*)* typeIdx, rBase);
308 // TUNING: fast path should fall through
309 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
310 loadWordDisp(cUnit, rSELF,
311 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
312 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700313 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700314 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
315 skipTarget->defMask = ENCODE_ALL;
316 branchOver->generic.target = (LIR*)skipTarget;
317 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
318 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
319 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
320 rlSrc.highReg);
buzbee1da522d2011-09-04 11:22:20 -0700321 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700322 }
buzbee67bf8852011-08-17 17:51:35 -0700323}
324
325
buzbeeed3e9302011-09-23 17:34:19 -0700326STATIC void genSgetWide(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700327 RegLocation rlResult, RegLocation rlDest)
328{
buzbee1da522d2011-09-04 11:22:20 -0700329 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700330 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800331 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbee12246b82011-09-29 14:15:05 -0700332#if ANDROID_SMP != 0
333 bool isVolatile = (field == NULL) || field->IsVolatile();
334#else
335 bool isVolatile = false;
336#endif
buzbee6181f792011-09-29 11:14:04 -0700337 oatFlushAllRegs(cUnit);
buzbee12246b82011-09-29 14:15:05 -0700338 if (SLOW_FIELD_PATH || field == NULL || isVolatile) {
Elliott Hughes81bc5092011-09-30 17:25:59 -0700339 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700340 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700341 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
342 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700343 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700344 RegLocation rlResult = oatGetReturnWide(cUnit);
345 storeValueWide(cUnit, rlDest, rlResult);
346 } else {
buzbee1da522d2011-09-04 11:22:20 -0700347 // Fast path
348 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700349 // Using fixed register to sync with slow path
350 int rMethod = r1;
351 oatLockTemp(cUnit, rMethod);
352 loadCurrMethodDirect(cUnit, rMethod);
353 int rBase = r0;
354 oatLockTemp(cUnit, rBase);
355 loadWordDisp(cUnit, rMethod,
356 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
357 rBase);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800358 loadWordDisp(cUnit, rBase, Array::DataOffset().Int32Value() +
buzbee1da522d2011-09-04 11:22:20 -0700359 sizeof(int32_t*)* typeIdx, rBase);
360 // TUNING: fast path should fall through
361 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
362 loadWordDisp(cUnit, rSELF,
363 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
364 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700365 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700366 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
367 skipTarget->defMask = ENCODE_ALL;
368 branchOver->generic.target = (LIR*)skipTarget;
369 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
370 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee1da522d2011-09-04 11:22:20 -0700371 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
372 rlResult.highReg, INVALID_SREG);
373 oatFreeTemp(cUnit, rBase);
374 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700375 }
buzbee67bf8852011-08-17 17:51:35 -0700376}
377
buzbeeed3e9302011-09-23 17:34:19 -0700378STATIC void genSget(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700379 RegLocation rlResult, RegLocation rlDest)
380{
buzbee1da522d2011-09-04 11:22:20 -0700381 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700382 uint32_t typeIdx;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800383 Field* field = FindFieldWithResolvedStaticStorage(cUnit, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700384 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
385 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee6181f792011-09-29 11:14:04 -0700386 oatFlushAllRegs(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700387 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700388 // Slow path
Elliott Hughes81bc5092011-09-30 17:25:59 -0700389 warnIfUnresolved(cUnit, fieldIdx, field);
buzbee1da522d2011-09-04 11:22:20 -0700390 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
391 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700392 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
393 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
394 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700395 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700396 RegLocation rlResult = oatGetReturn(cUnit);
397 storeValue(cUnit, rlDest, rlResult);
398 } else {
buzbee1da522d2011-09-04 11:22:20 -0700399 // Fast path
400 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700401 // Using fixed register to sync with slow path
402 int rMethod = r1;
403 oatLockTemp(cUnit, rMethod);
404 loadCurrMethodDirect(cUnit, rMethod);
405 int rBase = r0;
406 oatLockTemp(cUnit, rBase);
407 loadWordDisp(cUnit, rMethod,
408 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
409 rBase);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800410 loadWordDisp(cUnit, rBase, Array::DataOffset().Int32Value() +
buzbee1da522d2011-09-04 11:22:20 -0700411 sizeof(int32_t*)* typeIdx, rBase);
412 // TUNING: fast path should fall through
413 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
414 loadWordDisp(cUnit, rSELF,
415 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
416 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700417 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700418 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
419 skipTarget->defMask = ENCODE_ALL;
420 branchOver->generic.target = (LIR*)skipTarget;
421 rlDest = oatGetDest(cUnit, mir, 0);
422 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700423#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700424 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700425 oatGenMemBarrier(cUnit, kSY);
426 }
buzbee67bf8852011-08-17 17:51:35 -0700427#endif
buzbee1da522d2011-09-04 11:22:20 -0700428 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
429 oatFreeTemp(cUnit, rBase);
430 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700431 }
buzbee67bf8852011-08-17 17:51:35 -0700432}
433
buzbee561227c2011-09-02 15:28:19 -0700434typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
435 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700436
437/*
438 * Bit of a hack here - in leiu of a real scheduling pass,
439 * emit the next instruction in static & direct invoke sequences.
440 */
buzbeeed3e9302011-09-23 17:34:19 -0700441STATIC int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700442 DecodedInstruction* dInsn, int state,
443 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700444{
buzbee561227c2011-09-02 15:28:19 -0700445 DCHECK(rollback == NULL);
446 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700447 switch(state) {
448 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700449 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700450 break;
buzbee561227c2011-09-02 15:28:19 -0700451 case 1: // Get method->code_and_direct_methods_
452 loadWordDisp(cUnit, r0,
453 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
454 r0);
buzbee67bf8852011-08-17 17:51:35 -0700455 break;
buzbee561227c2011-09-02 15:28:19 -0700456 case 2: // Grab target method* and target code_
457 loadWordDisp(cUnit, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800458 CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
buzbee561227c2011-09-02 15:28:19 -0700459 loadWordDisp(cUnit, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800460 CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700461 break;
462 default:
463 return -1;
464 }
465 return state + 1;
466}
467
buzbee67bf8852011-08-17 17:51:35 -0700468/*
469 * Bit of a hack here - in leiu of a real scheduling pass,
470 * emit the next instruction in a virtual invoke sequence.
471 * We can use rLR as a temp prior to target address loading
472 * Note also that we'll load the first argument ("this") into
473 * r1 here rather than the standard loadArgRegs.
474 */
buzbeeed3e9302011-09-23 17:34:19 -0700475STATIC int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700476 DecodedInstruction* dInsn, int state,
477 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700478{
buzbee561227c2011-09-02 15:28:19 -0700479 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700480 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700481 /*
482 * This is the fast path in which the target virtual method is
483 * fully resolved at compile time.
484 */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800485 Method* baseMethod = cUnit->class_linker->ResolveMethod(*cUnit->dex_file,
486 dInsn->vB,
487 cUnit->dex_cache,
488 cUnit->class_loader,
489 false);
buzbee561227c2011-09-02 15:28:19 -0700490 CHECK(baseMethod != NULL);
491 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700492 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700493 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700494 rlArg = oatGetSrc(cUnit, mir, 0);
495 loadValueDirectFixed(cUnit, rlArg, r1);
496 break;
buzbee561227c2011-09-02 15:28:19 -0700497 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700498 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700499 // get this->klass_ [use r1, set rLR]
500 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700501 break;
buzbee561227c2011-09-02 15:28:19 -0700502 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
503 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700504 break;
buzbee561227c2011-09-02 15:28:19 -0700505 case 3: // Get target method [use rLR, set r0]
506 loadWordDisp(cUnit, rLR, (target_idx * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800507 Array::DataOffset().Int32Value(), r0);
buzbee561227c2011-09-02 15:28:19 -0700508 break;
509 case 4: // Get the target compiled code address [uses r0, sets rLR]
510 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700511 break;
512 default:
513 return -1;
514 }
515 return state + 1;
516}
517
buzbeeed3e9302011-09-23 17:34:19 -0700518STATIC int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700519 DecodedInstruction* dInsn, int state,
520 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700521{
522 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700523 ArmLIR* skipBranch;
524 ArmLIR* skipTarget;
525 /*
526 * This handles the case in which the base method is not fully
527 * resolved at compile time. We must generate code to test
528 * for resolution a run time, bail to the slow path if not to
529 * fill in all the tables. In the latter case, we'll restart at
530 * at the beginning of the sequence.
531 */
buzbee7b1b86d2011-08-26 18:59:10 -0700532 switch(state) {
533 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700534 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700535 break;
buzbee561227c2011-09-02 15:28:19 -0700536 case 1: // Get method->dex_cache_resolved_methods_
537 loadWordDisp(cUnit, r0,
538 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700539 break;
buzbee561227c2011-09-02 15:28:19 -0700540 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
541 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800542 Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700543 break;
buzbee561227c2011-09-02 15:28:19 -0700544 case 3: // Resolved?
545 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
546 // Slowest path, bail to helper, rollback and retry
547 loadWordDisp(cUnit, rSELF,
548 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
549 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -0800550 loadConstant(cUnit, r2, false);
Ian Rogersff1ed472011-09-20 13:46:24 -0700551 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700552 genUnconditionalBranch(cUnit, rollback);
553 // Resume normal slow path
554 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
555 skipTarget->defMask = ENCODE_ALL;
556 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700557 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700558 loadBaseDisp(cUnit, mir, rLR,
559 Method::GetMethodIndexOffset().Int32Value(), r0,
560 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700561 // Load "this" [set r1]
562 rlArg = oatGetSrc(cUnit, mir, 0);
563 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700564 break;
565 case 4:
566 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700567 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700568 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700569 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700570 break;
buzbee561227c2011-09-02 15:28:19 -0700571 case 5:
572 // get this->klass_->vtable_ [usr rLR, set rLR]
573 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800574 DCHECK_EQ((Array::DataOffset().Int32Value() & 0x3), 0);
buzbee561227c2011-09-02 15:28:19 -0700575 // In load shadow fold vtable_ object header size into method_index_
576 opRegImm(cUnit, kOpAdd, r0,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800577 Array::DataOffset().Int32Value() / 4);
buzbee561227c2011-09-02 15:28:19 -0700578 // Get target Method*
579 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
580 break;
581 case 6: // Get the target compiled code address [uses r0, sets rLR]
582 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700583 break;
584 default:
585 return -1;
586 }
587 return state + 1;
588}
589
buzbeeed3e9302011-09-23 17:34:19 -0700590STATIC int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
buzbeec0ecd652011-09-25 18:11:54 -0700591 DecodedInstruction* dInsn, int callState,
592 NextCallInsn nextCallInsn, ArmLIR* rollback,
593 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700594{
buzbeec0ecd652011-09-25 18:11:54 -0700595 int nextReg = r1;
596 int nextArg = 0;
597 if (skipThis) {
598 nextReg++;
599 nextArg++;
600 }
601 for (; (nextReg <= r3) && (nextArg < mir->ssaRep->numUses); nextReg++) {
602 RegLocation rlArg = oatGetRawSrc(cUnit, mir, nextArg++);
603 rlArg = oatUpdateRawLoc(cUnit, rlArg);
604 if (rlArg.wide && (nextReg <= r2)) {
605 loadValueDirectWideFixed(cUnit, rlArg, nextReg, nextReg + 1);
606 nextReg++;
607 nextArg++;
608 } else {
buzbee1b4c8592011-08-31 10:43:51 -0700609 rlArg.wide = false;
buzbeec0ecd652011-09-25 18:11:54 -0700610 loadValueDirectFixed(cUnit, rlArg, nextReg);
buzbee67bf8852011-08-17 17:51:35 -0700611 }
buzbeec0ecd652011-09-25 18:11:54 -0700612 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700613 }
614 return callState;
615}
616
buzbee4a3164f2011-09-03 11:25:10 -0700617// Interleave launch code for INVOKE_INTERFACE.
buzbeeed3e9302011-09-23 17:34:19 -0700618STATIC int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700619 DecodedInstruction* dInsn, int state,
620 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700621{
buzbee510c6052011-10-27 10:47:20 -0700622 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700623 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700624 case 0: // Load trampoline target
625 loadWordDisp(cUnit, rSELF,
626 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
627 rLR);
628 // Load r0 with method index
629 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700630 break;
buzbee67bf8852011-08-17 17:51:35 -0700631 default:
632 return -1;
633 }
634 return state + 1;
635}
636
buzbee67bf8852011-08-17 17:51:35 -0700637/*
638 * Interleave launch code for INVOKE_SUPER. See comments
639 * for nextVCallIns.
640 */
buzbeeed3e9302011-09-23 17:34:19 -0700641STATIC int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700642 DecodedInstruction* dInsn, int state,
643 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700644{
buzbee4a3164f2011-09-03 11:25:10 -0700645 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700646 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700647 /*
648 * This is the fast path in which the target virtual method is
649 * fully resolved at compile time. Note also that this path assumes
650 * that the check to verify that the target method index falls
651 * within the size of the super's vtable has been done at compile-time.
652 */
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800653 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -0800654 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
655 dInsn->vB,
656 cUnit->dex_cache,
657 cUnit->class_loader,
658 false);
buzbee4a3164f2011-09-03 11:25:10 -0700659 CHECK(baseMethod != NULL);
Ian Rogersa3760aa2011-11-14 14:32:37 -0800660 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
661 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
662 Class* superClass = (declaring_class != NULL)
663 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -0700664 CHECK(superClass != NULL);
665 int32_t target_idx = baseMethod->GetMethodIndex();
666 CHECK(superClass->GetVTable()->GetLength() > target_idx);
667 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
668 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700669 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700670 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700671 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700672 // Load "this" [set r1]
673 rlArg = oatGetSrc(cUnit, mir, 0);
674 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700675 // Get method->declaring_class_ [use r0, set rLR]
676 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
677 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700678 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700679 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700680 break;
681 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
682 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
683 rLR);
684 break;
685 case 2: // Get ...->super_class_->vtable [u/s rLR]
686 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
687 break;
688 case 3: // Get target method [use rLR, set r0]
689 loadWordDisp(cUnit, rLR, (target_idx * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800690 Array::DataOffset().Int32Value(), r0);
buzbee4a3164f2011-09-03 11:25:10 -0700691 break;
692 case 4: // Get the target compiled code address [uses r0, sets rLR]
693 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
694 break;
buzbee67bf8852011-08-17 17:51:35 -0700695 default:
696 return -1;
697 }
buzbee4a3164f2011-09-03 11:25:10 -0700698 return state + 1;
699}
700
701/* Slow-path version of nextSuperCallInsn */
buzbeeed3e9302011-09-23 17:34:19 -0700702STATIC int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee4a3164f2011-09-03 11:25:10 -0700703 DecodedInstruction* dInsn, int state,
704 ArmLIR* rollback)
705{
buzbee4a3164f2011-09-03 11:25:10 -0700706 RegLocation rlArg;
707 ArmLIR* skipBranch;
708 ArmLIR* skipTarget;
709 int tReg;
710 /*
711 * This handles the case in which the base method is not fully
712 * resolved at compile time. We must generate code to test
713 * for resolution a run time, bail to the slow path if not to
714 * fill in all the tables. In the latter case, we'll restart at
715 * at the beginning of the sequence.
716 */
717 switch(state) {
718 case 0: // Get the current Method* [sets r0]
719 loadCurrMethodDirect(cUnit, r0);
720 break;
buzbee34c77ad2012-01-11 13:01:32 -0800721 case 1: // Get method->dex_cache_resolved_methods_ [uses r0, set rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700722 loadWordDisp(cUnit, r0,
723 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
724 break;
725 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
726 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800727 Array::DataOffset().Int32Value(), rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700728 break;
729 case 3: // Resolved?
730 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
731 // Slowest path, bail to helper, rollback and retry
732 loadWordDisp(cUnit, rSELF,
733 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
734 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -0800735 loadConstant(cUnit, r2, true);
Ian Rogersff1ed472011-09-20 13:46:24 -0700736 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700737 genUnconditionalBranch(cUnit, rollback);
738 // Resume normal slow path
739 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
740 skipTarget->defMask = ENCODE_ALL;
741 skipBranch->generic.target = (LIR*)skipTarget;
742 // Get base_method->method_index [usr rLR, set rLR]
743 loadBaseDisp(cUnit, mir, rLR,
744 Method::GetMethodIndexOffset().Int32Value(), rLR,
745 kUnsignedHalf, INVALID_SREG);
746 // Load "this" [set r1]
747 rlArg = oatGetSrc(cUnit, mir, 0);
748 loadValueDirectFixed(cUnit, rlArg, r1);
749 // Load curMethod->declaring_class_ [uses r0, sets r0]
750 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
751 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700752 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700753 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700754 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700755 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
756 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700757 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700758 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700759 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700760 // Range check, throw NSM on failure
761 tReg = oatAllocTemp(cUnit);
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800762 loadWordDisp(cUnit, r0, Array::LengthOffset().Int32Value(),
buzbee4a3164f2011-09-03 11:25:10 -0700763 tReg);
buzbee13ac45a2012-01-12 12:30:16 -0800764 genRegRegCheck(cUnit, kArmCondCs, rLR, tReg, mir,
buzbeeec5adf32011-09-11 15:25:43 -0700765 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700766 oatFreeTemp(cUnit, tReg);
767 }
buzbee6a0f7f52011-09-05 16:14:20 -0700768 // Adjust vtable_ base past object header
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800769 opRegImm(cUnit, kOpAdd, r0, Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700770 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700771 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700772 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700773 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700774 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
775 break;
776 default:
777 return -1;
778 }
buzbee67bf8852011-08-17 17:51:35 -0700779 return state + 1;
780}
781
782/*
783 * Load up to 5 arguments, the first three of which will be in
784 * r1 .. r3. On entry r0 contains the current method pointer,
785 * and as part of the load sequence, it must be replaced with
786 * the target method pointer. Note, this may also be called
787 * for "range" variants if the number of arguments is 5 or fewer.
788 */
buzbeeed3e9302011-09-23 17:34:19 -0700789STATIC int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700790 DecodedInstruction* dInsn, int callState,
791 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700792 NextCallInsn nextCallInsn, ArmLIR* rollback,
793 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700794{
795 RegLocation rlArg;
buzbee67bf8852011-08-17 17:51:35 -0700796
797 /* If no arguments, just return */
798 if (dInsn->vA == 0)
799 return callState;
800
buzbee561227c2011-09-02 15:28:19 -0700801 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700802
buzbeec0ecd652011-09-25 18:11:54 -0700803 DCHECK_LE(dInsn->vA, 5U);
804 if (dInsn->vA > 3) {
805 uint32_t nextUse = 3;
806 //Detect special case of wide arg spanning arg3/arg4
807 RegLocation rlUse0 = oatGetRawSrc(cUnit, mir, 0);
808 RegLocation rlUse1 = oatGetRawSrc(cUnit, mir, 1);
809 RegLocation rlUse2 = oatGetRawSrc(cUnit, mir, 2);
810 if (((!rlUse0.wide && !rlUse1.wide) || rlUse0.wide) &&
811 rlUse2.wide) {
812 int reg;
813 // Wide spans, we need the 2nd half of uses[2].
814 rlArg = oatUpdateLocWide(cUnit, rlUse2);
815 if (rlArg.location == kLocPhysReg) {
816 reg = rlArg.highReg;
817 } else {
818 // r2 & r3 can safely be used here
819 reg = r3;
buzbee67bc2362011-10-11 18:08:40 -0700820 loadWordDisp(cUnit, rSP,
821 oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
buzbeec0ecd652011-09-25 18:11:54 -0700822 callState = nextCallInsn(cUnit, mir, dInsn, callState,
823 rollback);
824 }
825 storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
826 storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
827 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
828 nextUse++;
829 }
830 // Loop through the rest
831 while (nextUse < dInsn->vA) {
832 int lowReg;
833 int highReg;
834 rlArg = oatGetRawSrc(cUnit, mir, nextUse);
835 rlArg = oatUpdateRawLoc(cUnit, rlArg);
836 if (rlArg.location == kLocPhysReg) {
837 lowReg = rlArg.lowReg;
838 highReg = rlArg.highReg;
839 } else {
840 lowReg = r2;
841 highReg = r3;
842 if (rlArg.wide) {
843 loadValueDirectWideFixed(cUnit, rlArg, lowReg, highReg);
844 } else {
845 loadValueDirectFixed(cUnit, rlArg, lowReg);
846 }
847 callState = nextCallInsn(cUnit, mir, dInsn, callState,
848 rollback);
849 }
850 int outsOffset = (nextUse + 1) * 4;
851 if (rlArg.wide) {
852 storeBaseDispWide(cUnit, rSP, outsOffset, lowReg, highReg);
853 nextUse += 2;
854 } else {
855 storeWordDisp(cUnit, rSP, outsOffset, lowReg);
856 nextUse++;
857 }
buzbee561227c2011-09-02 15:28:19 -0700858 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700859 }
buzbee67bf8852011-08-17 17:51:35 -0700860 }
861
buzbeec0ecd652011-09-25 18:11:54 -0700862 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
863 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700864
buzbee67bf8852011-08-17 17:51:35 -0700865 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700866 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700867 }
868 return callState;
869}
870
871/*
872 * May have 0+ arguments (also used for jumbo). Note that
873 * source virtual registers may be in physical registers, so may
874 * need to be flushed to home location before copying. This
875 * applies to arg3 and above (see below).
876 *
877 * Two general strategies:
878 * If < 20 arguments
879 * Pass args 3-18 using vldm/vstm block copy
880 * Pass arg0, arg1 & arg2 in r1-r3
881 * If 20+ arguments
882 * Pass args arg19+ using memcpy block copy
883 * Pass arg0, arg1 & arg2 in r1-r3
884 *
885 */
buzbeeed3e9302011-09-23 17:34:19 -0700886STATIC int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -0700887 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700888 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700889 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700890{
891 int firstArg = dInsn->vC;
892 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700893
buzbee67bf8852011-08-17 17:51:35 -0700894 // If we can treat it as non-range (Jumbo ops will use range form)
895 if (numArgs <= 5)
896 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700897 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700898 /*
899 * Make sure range list doesn't span the break between in normal
900 * Dalvik vRegs and the ins.
901 */
buzbee1b4c8592011-08-31 10:43:51 -0700902 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800903 int boundaryReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee1b4c8592011-08-31 10:43:51 -0700904 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
905 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700906 }
907
908 /*
909 * First load the non-register arguments. Both forms expect all
910 * of the source arguments to be in their home frame location, so
911 * scan the sReg names and flush any that have been promoted to
912 * frame backing storage.
913 */
914 // Scan the rest of the args - if in physReg flush to memory
buzbeec0ecd652011-09-25 18:11:54 -0700915 for (int nextArg = 0; nextArg < numArgs;) {
916 RegLocation loc = oatGetRawSrc(cUnit, mir, nextArg);
buzbee1b4c8592011-08-31 10:43:51 -0700917 if (loc.wide) {
918 loc = oatUpdateLocWide(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700919 if ((nextArg >= 2) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700920 storeBaseDispWide(cUnit, rSP,
921 oatSRegOffset(cUnit, loc.sRegLow),
922 loc.lowReg, loc.highReg);
buzbee1b4c8592011-08-31 10:43:51 -0700923 }
buzbeec0ecd652011-09-25 18:11:54 -0700924 nextArg += 2;
buzbee1b4c8592011-08-31 10:43:51 -0700925 } else {
926 loc = oatUpdateLoc(cUnit, loc);
buzbeec0ecd652011-09-25 18:11:54 -0700927 if ((nextArg >= 3) && (loc.location == kLocPhysReg)) {
buzbee67bc2362011-10-11 18:08:40 -0700928 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, loc.sRegLow),
929 loc.lowReg, kWord);
buzbee1b4c8592011-08-31 10:43:51 -0700930 }
buzbeec0ecd652011-09-25 18:11:54 -0700931 nextArg++;
buzbee67bf8852011-08-17 17:51:35 -0700932 }
933 }
934
buzbee67bc2362011-10-11 18:08:40 -0700935 int startOffset = oatSRegOffset(cUnit,
936 cUnit->regLocation[mir->ssaRep->uses[3]].sRegLow);
buzbee67bf8852011-08-17 17:51:35 -0700937 int outsOffset = 4 /* Method* */ + (3 * 4);
938 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700939 // Generate memcpy
940 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
941 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700942 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
943 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700944 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700945 // Restore Method*
946 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700947 } else {
948 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700949 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700950 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700951 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700952 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
953 //TUNING: loosen barrier
954 ld->defMask = ENCODE_ALL;
955 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700956 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700957 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700958 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700959 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
960 setMemRefType(st, false /* isLoad */, kDalvikReg);
961 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700962 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700963 }
964
buzbeec0ecd652011-09-25 18:11:54 -0700965 callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
966 rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700967
buzbee561227c2011-09-02 15:28:19 -0700968 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee99f27232011-10-05 12:56:36 -0700969 if (pcrLabel) {
970 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
971 }
buzbee67bf8852011-08-17 17:51:35 -0700972 return callState;
973}
974
buzbee2a475e72011-09-07 17:19:17 -0700975// Debugging routine - if null target, branch to DebugMe
buzbeeed3e9302011-09-23 17:34:19 -0700976STATIC void genShowTarget(CompilationUnit* cUnit)
buzbee2a475e72011-09-07 17:19:17 -0700977{
978 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
979 loadWordDisp(cUnit, rSELF,
980 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
981 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
982 target->defMask = -1;
983 branchOver->generic.target = (LIR*)target;
984}
buzbee2a475e72011-09-07 17:19:17 -0700985
buzbeeed3e9302011-09-23 17:34:19 -0700986STATIC void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700987 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700988{
989 DecodedInstruction* dInsn = &mir->dalvikInsn;
990 int callState = 0;
991 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700992 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700993 NextCallInsn nextCallInsn = nextSDCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -0700994 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee561227c2011-09-02 15:28:19 -0700995
buzbee109bd6a2011-09-06 13:58:41 -0700996 // Explicit register usage
997 oatLockCallTemps(cUnit);
998
buzbee99f27232011-10-05 12:56:36 -0700999 // Is this the special "Ljava/lang/Object;.<init>:()V" case?
1000 if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT) {
1001 int idx = mir->dalvikInsn.vB;
Ian Rogersa3760aa2011-11-14 14:32:37 -08001002 Method* target = cUnit->dex_cache->GetResolvedMethods()->Get(idx);
buzbee99f27232011-10-05 12:56:36 -07001003 if (target) {
1004 if (PrettyMethod(target) == "java.lang.Object.<init>()V") {
1005 RegLocation rlArg = oatGetSrc(cUnit, mir, 0);
1006 loadValueDirectFixed(cUnit, rlArg, r0);
1007 loadWordDisp(cUnit, rSELF,
1008 OFFSETOF_MEMBER(Thread, pObjectInit), rLR);
1009 genNullCheck(cUnit, oatSSASrc(mir,0), r0, mir);
1010 opReg(cUnit, kOpBlx, rLR);
1011 oatClobberCalleeSave(cUnit);
1012 return;
1013 }
1014 }
1015 }
1016
buzbee561227c2011-09-02 15:28:19 -07001017 if (range) {
1018 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -07001019 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -07001020 } else {
1021 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -07001022 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -07001023 }
buzbee67bf8852011-08-17 17:51:35 -07001024 // Finish up any of the call sequence not interleaved in arg loading
1025 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001026 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001027 }
buzbeece302932011-10-04 14:32:18 -07001028 if (DISPLAY_MISSING_TARGETS) {
1029 genShowTarget(cUnit);
1030 }
buzbeeec5adf32011-09-11 15:25:43 -07001031 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001032 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001033}
1034
buzbee4a3164f2011-09-03 11:25:10 -07001035/*
1036 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
1037 * which will locate the target and continue on via a tail call.
1038 */
buzbeeed3e9302011-09-23 17:34:19 -07001039STATIC void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001040{
1041 DecodedInstruction* dInsn = &mir->dalvikInsn;
1042 int callState = 0;
1043 ArmLIR* nullCk;
buzbeec0ecd652011-09-25 18:11:54 -07001044 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001045
1046 // Explicit register usage
1047 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001048 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -07001049 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001050 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
1051 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001052 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -07001053 false);
buzbee67bf8852011-08-17 17:51:35 -07001054 else
1055 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -07001056 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -07001057 // Finish up any of the call sequence not interleaved in arg loading
1058 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001059 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -07001060 }
buzbeece302932011-10-04 14:32:18 -07001061 if (DISPLAY_MISSING_TARGETS) {
1062 genShowTarget(cUnit);
1063 }
buzbeeec5adf32011-09-11 15:25:43 -07001064 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001065 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001066}
1067
buzbeeed3e9302011-09-23 17:34:19 -07001068STATIC void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001069{
1070 DecodedInstruction* dInsn = &mir->dalvikInsn;
1071 int callState = 0;
buzbee4a3164f2011-09-03 11:25:10 -07001072 ArmLIR* rollback;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001073 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001074 Method* baseMethod = class_linker->ResolveMethod(*cUnit->dex_file,
1075 dInsn->vB,
1076 cUnit->dex_cache,
1077 cUnit->class_loader,
1078 false);
buzbee4a3164f2011-09-03 11:25:10 -07001079 NextCallInsn nextCallInsn;
1080 bool fastPath = true;
buzbeec0ecd652011-09-25 18:11:54 -07001081 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001082
1083 // Explicit register usage
1084 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -08001085
1086 // For testing, force call to artResolveMethodFromCode & ignore result
1087 if (EXERCISE_RESOLVE_METHOD) {
1088 loadCurrMethodDirect(cUnit, r0);
1089 loadWordDisp(cUnit, rSELF,
1090 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
1091 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -08001092 loadConstant(cUnit, r2, true);
buzbee34c77ad2012-01-11 13:01:32 -08001093 callRuntimeHelper(cUnit, rLR);
1094 }
1095
buzbee34cd9e52011-09-08 14:31:52 -07001096 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001097 Thread* thread = Thread::Current();
1098 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1099 thread->ClearException();
1100 }
buzbee4a3164f2011-09-03 11:25:10 -07001101 fastPath = false;
1102 } else {
Ian Rogersa3760aa2011-11-14 14:32:37 -08001103 Class* declaring_class = cUnit->dex_cache->GetResolvedTypes()
1104 ->Get(cUnit->dex_file->GetMethodId(cUnit->method_idx).class_idx_);
1105 Class* superClass = (declaring_class != NULL)
1106 ? declaring_class->GetSuperClass() : NULL;
buzbee4a3164f2011-09-03 11:25:10 -07001107 if (superClass == NULL) {
1108 fastPath = false;
1109 } else {
1110 int32_t target_idx = baseMethod->GetMethodIndex();
1111 if (superClass->GetVTable()->GetLength() <= target_idx) {
1112 fastPath = false;
1113 } else {
1114 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
1115 }
1116 }
1117 }
1118 if (fastPath) {
1119 nextCallInsn = nextSuperCallInsn;
1120 rollback = NULL;
1121 } else {
1122 nextCallInsn = nextSuperCallInsnSP;
1123 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1124 rollback->defMask = -1;
1125 }
buzbee67bf8852011-08-17 17:51:35 -07001126 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
buzbeec0ecd652011-09-25 18:11:54 -07001127 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001128 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001129 else
buzbeec0ecd652011-09-25 18:11:54 -07001130 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001131 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001132 // Finish up any of the call sequence not interleaved in arg loading
1133 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001134 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001135 }
buzbeece302932011-10-04 14:32:18 -07001136 if (DISPLAY_MISSING_TARGETS) {
1137 genShowTarget(cUnit);
1138 }
buzbeeec5adf32011-09-11 15:25:43 -07001139 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001140 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001141}
1142
buzbeeed3e9302011-09-23 17:34:19 -07001143STATIC void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001144{
1145 DecodedInstruction* dInsn = &mir->dalvikInsn;
1146 int callState = 0;
buzbee561227c2011-09-02 15:28:19 -07001147 ArmLIR* rollback;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001148 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Ian Rogersa3760aa2011-11-14 14:32:37 -08001149 Method* method = class_linker->ResolveMethod(*cUnit->dex_file,
1150 dInsn->vB,
1151 cUnit->dex_cache,
1152 cUnit->class_loader,
1153 false);
buzbee561227c2011-09-02 15:28:19 -07001154 NextCallInsn nextCallInsn;
buzbeec0ecd652011-09-25 18:11:54 -07001155 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbee109bd6a2011-09-06 13:58:41 -07001156 // Explicit register usage
1157 oatLockCallTemps(cUnit);
buzbee34c77ad2012-01-11 13:01:32 -08001158
1159 // For testing, force call to artResolveMethodFromCode & ignore result
1160 if (EXERCISE_RESOLVE_METHOD) {
1161 loadCurrMethodDirect(cUnit, r0);
1162 loadWordDisp(cUnit, rSELF,
1163 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
1164 loadConstant(cUnit, r1, dInsn->vB);
buzbee48d72222012-01-11 15:19:51 -08001165 loadConstant(cUnit, r2, false);
buzbee34c77ad2012-01-11 13:01:32 -08001166 callRuntimeHelper(cUnit, rLR);
1167 }
1168
buzbee34cd9e52011-09-08 14:31:52 -07001169 if (SLOW_INVOKE_PATH || method == NULL) {
Ian Rogersbd441352011-10-31 10:49:47 -07001170 Thread* thread = Thread::Current();
1171 if (thread->IsExceptionPending()) { // clear any exception left by resolve method
1172 thread->ClearException();
1173 }
buzbee561227c2011-09-02 15:28:19 -07001174 // Slow path
1175 nextCallInsn = nextVCallInsnSP;
1176 // If we need a slow-path callout, we'll restart here
1177 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1178 rollback->defMask = -1;
1179 } else {
1180 // Fast path
1181 nextCallInsn = nextVCallInsn;
1182 rollback = NULL;
1183 }
buzbee67bf8852011-08-17 17:51:35 -07001184 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
buzbeec0ecd652011-09-25 18:11:54 -07001185 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001186 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001187 else
buzbeec0ecd652011-09-25 18:11:54 -07001188 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, NULL,
buzbee1da522d2011-09-04 11:22:20 -07001189 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001190 // Finish up any of the call sequence not interleaved in arg loading
1191 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001192 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001193 }
buzbeece302932011-10-04 14:32:18 -07001194 if (DISPLAY_MISSING_TARGETS) {
1195 genShowTarget(cUnit);
1196 }
buzbeeec5adf32011-09-11 15:25:43 -07001197 opReg(cUnit, kOpBlx, rLR);
buzbee6181f792011-09-29 11:14:04 -07001198 oatClobberCalleeSave(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001199}
1200
buzbeeed3e9302011-09-23 17:34:19 -07001201STATIC bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
buzbee67bf8852011-08-17 17:51:35 -07001202 BasicBlock* bb, ArmLIR* labelList)
1203{
1204 bool res = false; // Assume success
1205 RegLocation rlSrc[3];
1206 RegLocation rlDest = badLoc;
1207 RegLocation rlResult = badLoc;
1208 Opcode opcode = mir->dalvikInsn.opcode;
1209
1210 /* Prep Src and Dest locations */
1211 int nextSreg = 0;
1212 int nextLoc = 0;
1213 int attrs = oatDataFlowAttributes[opcode];
1214 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1215 if (attrs & DF_UA) {
1216 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1217 nextSreg++;
1218 } else if (attrs & DF_UA_WIDE) {
1219 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1220 nextSreg + 1);
1221 nextSreg+= 2;
1222 }
1223 if (attrs & DF_UB) {
1224 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1225 nextSreg++;
1226 } else if (attrs & DF_UB_WIDE) {
1227 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1228 nextSreg + 1);
1229 nextSreg+= 2;
1230 }
1231 if (attrs & DF_UC) {
1232 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1233 } else if (attrs & DF_UC_WIDE) {
1234 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1235 nextSreg + 1);
1236 }
1237 if (attrs & DF_DA) {
1238 rlDest = oatGetDest(cUnit, mir, 0);
1239 } else if (attrs & DF_DA_WIDE) {
1240 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1241 }
1242
1243 switch(opcode) {
1244 case OP_NOP:
1245 break;
1246
1247 case OP_MOVE_EXCEPTION:
1248 int exOffset;
1249 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001250 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001251 resetReg = oatAllocTemp(cUnit);
1252 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1253 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1254 loadConstant(cUnit, resetReg, 0);
1255 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1256 storeValue(cUnit, rlDest, rlResult);
1257 break;
1258
1259 case OP_RETURN_VOID:
buzbeefe2e17f2011-10-10 09:35:02 -07001260 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001261 break;
1262
1263 case OP_RETURN:
1264 case OP_RETURN_OBJECT:
buzbeefe2e17f2011-10-10 09:35:02 -07001265 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001266 storeValue(cUnit, getRetLoc(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001267 break;
1268
1269 case OP_RETURN_WIDE:
buzbeefe2e17f2011-10-10 09:35:02 -07001270 genSuspendTest(cUnit, mir);
buzbee6181f792011-09-29 11:14:04 -07001271 storeValueWide(cUnit, getRetLocWide(cUnit), rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001272 break;
1273
1274 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001275 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001276 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001277 storeValueWide(cUnit, rlDest, getRetLocWide(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001278 break;
1279
1280 case OP_MOVE_RESULT:
1281 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001282 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001283 break; // Nop - combined w/ previous invoke
buzbee6181f792011-09-29 11:14:04 -07001284 storeValue(cUnit, rlDest, getRetLoc(cUnit));
buzbee67bf8852011-08-17 17:51:35 -07001285 break;
1286
1287 case OP_MOVE:
1288 case OP_MOVE_OBJECT:
1289 case OP_MOVE_16:
1290 case OP_MOVE_OBJECT_16:
1291 case OP_MOVE_FROM16:
1292 case OP_MOVE_OBJECT_FROM16:
1293 storeValue(cUnit, rlDest, rlSrc[0]);
1294 break;
1295
1296 case OP_MOVE_WIDE:
1297 case OP_MOVE_WIDE_16:
1298 case OP_MOVE_WIDE_FROM16:
1299 storeValueWide(cUnit, rlDest, rlSrc[0]);
1300 break;
1301
1302 case OP_CONST:
1303 case OP_CONST_4:
1304 case OP_CONST_16:
1305 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1306 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1307 storeValue(cUnit, rlDest, rlResult);
1308 break;
1309
1310 case OP_CONST_HIGH16:
1311 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1312 loadConstantNoClobber(cUnit, rlResult.lowReg,
1313 mir->dalvikInsn.vB << 16);
1314 storeValue(cUnit, rlDest, rlResult);
1315 break;
1316
1317 case OP_CONST_WIDE_16:
1318 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001319 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1320 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1321 mir->dalvikInsn.vB,
1322 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001323 storeValueWide(cUnit, rlDest, rlResult);
1324 break;
1325
1326 case OP_CONST_WIDE:
1327 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1328 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001329 mir->dalvikInsn.vB_wide & 0xffffffff,
1330 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001331 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001332 break;
1333
1334 case OP_CONST_WIDE_HIGH16:
1335 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1336 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1337 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001338 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001339 break;
1340
1341 case OP_MONITOR_ENTER:
1342 genMonitorEnter(cUnit, mir, rlSrc[0]);
1343 break;
1344
1345 case OP_MONITOR_EXIT:
1346 genMonitorExit(cUnit, mir, rlSrc[0]);
1347 break;
1348
1349 case OP_CHECK_CAST:
1350 genCheckCast(cUnit, mir, rlSrc[0]);
1351 break;
1352
1353 case OP_INSTANCE_OF:
1354 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1355 break;
1356
1357 case OP_NEW_INSTANCE:
1358 genNewInstance(cUnit, mir, rlDest);
1359 break;
1360
1361 case OP_THROW:
1362 genThrow(cUnit, mir, rlSrc[0]);
1363 break;
1364
buzbee5ade1d22011-09-09 14:44:52 -07001365 case OP_THROW_VERIFICATION_ERROR:
1366 loadWordDisp(cUnit, rSELF,
1367 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1368 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1369 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001370 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001371 break;
1372
buzbee67bf8852011-08-17 17:51:35 -07001373 case OP_ARRAY_LENGTH:
1374 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001375 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001376 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001377 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001378 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1379 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1380 rlResult.lowReg);
1381 storeValue(cUnit, rlDest, rlResult);
1382 break;
1383
1384 case OP_CONST_STRING:
1385 case OP_CONST_STRING_JUMBO:
1386 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1387 break;
1388
1389 case OP_CONST_CLASS:
1390 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1391 break;
1392
1393 case OP_FILL_ARRAY_DATA:
1394 genFillArrayData(cUnit, mir, rlSrc[0]);
1395 break;
1396
1397 case OP_FILLED_NEW_ARRAY:
1398 genFilledNewArray(cUnit, mir, false /* not range */);
1399 break;
1400
1401 case OP_FILLED_NEW_ARRAY_RANGE:
1402 genFilledNewArray(cUnit, mir, true /* range */);
1403 break;
1404
1405 case OP_NEW_ARRAY:
1406 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1407 break;
1408
1409 case OP_GOTO:
1410 case OP_GOTO_16:
1411 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001412 if (bb->taken->startOffset <= mir->offset) {
1413 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001414 }
1415 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1416 break;
1417
1418 case OP_PACKED_SWITCH:
1419 genPackedSwitch(cUnit, mir, rlSrc[0]);
1420 break;
1421
1422 case OP_SPARSE_SWITCH:
1423 genSparseSwitch(cUnit, mir, rlSrc[0]);
1424 break;
1425
1426 case OP_CMPL_FLOAT:
1427 case OP_CMPG_FLOAT:
1428 case OP_CMPL_DOUBLE:
1429 case OP_CMPG_DOUBLE:
1430 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1431 break;
1432
1433 case OP_CMP_LONG:
1434 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1435 break;
1436
1437 case OP_IF_EQ:
1438 case OP_IF_NE:
1439 case OP_IF_LT:
1440 case OP_IF_GE:
1441 case OP_IF_GT:
1442 case OP_IF_LE: {
1443 bool backwardBranch;
1444 ArmConditionCode cond;
1445 backwardBranch = (bb->taken->startOffset <= mir->offset);
1446 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001447 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001448 }
1449 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1450 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1451 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1452 switch(opcode) {
1453 case OP_IF_EQ:
1454 cond = kArmCondEq;
1455 break;
1456 case OP_IF_NE:
1457 cond = kArmCondNe;
1458 break;
1459 case OP_IF_LT:
1460 cond = kArmCondLt;
1461 break;
1462 case OP_IF_GE:
1463 cond = kArmCondGe;
1464 break;
1465 case OP_IF_GT:
1466 cond = kArmCondGt;
1467 break;
1468 case OP_IF_LE:
1469 cond = kArmCondLe;
1470 break;
1471 default:
1472 cond = (ArmConditionCode)0;
1473 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1474 }
1475 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1476 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1477 break;
1478 }
1479
1480 case OP_IF_EQZ:
1481 case OP_IF_NEZ:
1482 case OP_IF_LTZ:
1483 case OP_IF_GEZ:
1484 case OP_IF_GTZ:
1485 case OP_IF_LEZ: {
1486 bool backwardBranch;
1487 ArmConditionCode cond;
1488 backwardBranch = (bb->taken->startOffset <= mir->offset);
1489 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001490 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001491 }
1492 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1493 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1494 switch(opcode) {
1495 case OP_IF_EQZ:
1496 cond = kArmCondEq;
1497 break;
1498 case OP_IF_NEZ:
1499 cond = kArmCondNe;
1500 break;
1501 case OP_IF_LTZ:
1502 cond = kArmCondLt;
1503 break;
1504 case OP_IF_GEZ:
1505 cond = kArmCondGe;
1506 break;
1507 case OP_IF_GTZ:
1508 cond = kArmCondGt;
1509 break;
1510 case OP_IF_LEZ:
1511 cond = kArmCondLe;
1512 break;
1513 default:
1514 cond = (ArmConditionCode)0;
1515 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1516 }
1517 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1518 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1519 break;
1520 }
1521
1522 case OP_AGET_WIDE:
1523 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1524 break;
1525 case OP_AGET:
1526 case OP_AGET_OBJECT:
1527 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1528 break;
1529 case OP_AGET_BOOLEAN:
1530 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1531 rlDest, 0);
1532 break;
1533 case OP_AGET_BYTE:
1534 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1535 break;
1536 case OP_AGET_CHAR:
1537 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1538 rlDest, 1);
1539 break;
1540 case OP_AGET_SHORT:
1541 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1542 break;
1543 case OP_APUT_WIDE:
1544 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1545 break;
1546 case OP_APUT:
1547 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1548 break;
1549 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001550 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001551 break;
1552 case OP_APUT_SHORT:
1553 case OP_APUT_CHAR:
1554 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1555 rlSrc[0], 1);
1556 break;
1557 case OP_APUT_BYTE:
1558 case OP_APUT_BOOLEAN:
1559 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1560 rlSrc[0], 0);
1561 break;
1562
1563 case OP_IGET_WIDE:
1564 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001565 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001566 break;
1567
1568 case OP_IGET:
1569 case OP_IGET_VOLATILE:
1570 case OP_IGET_OBJECT:
1571 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001572 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001573 break;
1574
1575 case OP_IGET_BOOLEAN:
1576 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001577 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001578 break;
1579
1580 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001581 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001582 break;
1583
1584 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001585 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001586 break;
1587
1588 case OP_IPUT_WIDE:
1589 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001590 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001591 break;
1592
1593 case OP_IPUT_OBJECT:
1594 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001595 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001596 break;
1597
1598 case OP_IPUT:
1599 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001600 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001601 break;
1602
1603 case OP_IPUT_BOOLEAN:
1604 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001605 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001606 break;
1607
1608 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001609 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001610 break;
1611
1612 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001613 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001614 break;
1615
1616 case OP_SGET:
1617 case OP_SGET_OBJECT:
1618 case OP_SGET_BOOLEAN:
1619 case OP_SGET_BYTE:
1620 case OP_SGET_CHAR:
1621 case OP_SGET_SHORT:
1622 genSget(cUnit, mir, rlResult, rlDest);
1623 break;
1624
1625 case OP_SGET_WIDE:
1626 genSgetWide(cUnit, mir, rlResult, rlDest);
1627 break;
1628
1629 case OP_SPUT:
1630 case OP_SPUT_OBJECT:
1631 case OP_SPUT_BOOLEAN:
1632 case OP_SPUT_BYTE:
1633 case OP_SPUT_CHAR:
1634 case OP_SPUT_SHORT:
1635 genSput(cUnit, mir, rlSrc[0]);
1636 break;
1637
1638 case OP_SPUT_WIDE:
1639 genSputWide(cUnit, mir, rlSrc[0]);
1640 break;
1641
1642 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001643 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1644 true /*range*/);
1645 break;
buzbee67bf8852011-08-17 17:51:35 -07001646 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001647 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1648 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001649 break;
1650
1651 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001652 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1653 false /*range*/);
1654 break;
buzbee67bf8852011-08-17 17:51:35 -07001655 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001656 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1657 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001658 break;
1659
1660 case OP_INVOKE_VIRTUAL:
1661 case OP_INVOKE_VIRTUAL_RANGE:
1662 genInvokeVirtual(cUnit, mir);
1663 break;
1664
1665 case OP_INVOKE_SUPER:
1666 case OP_INVOKE_SUPER_RANGE:
1667 genInvokeSuper(cUnit, mir);
1668 break;
1669
1670 case OP_INVOKE_INTERFACE:
1671 case OP_INVOKE_INTERFACE_RANGE:
1672 genInvokeInterface(cUnit, mir);
1673 break;
1674
1675 case OP_NEG_INT:
1676 case OP_NOT_INT:
1677 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1678 break;
1679
1680 case OP_NEG_LONG:
1681 case OP_NOT_LONG:
1682 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1683 break;
1684
1685 case OP_NEG_FLOAT:
1686 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1687 break;
1688
1689 case OP_NEG_DOUBLE:
1690 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1691 break;
1692
1693 case OP_INT_TO_LONG:
1694 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1695 if (rlSrc[0].location == kLocPhysReg) {
1696 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1697 } else {
1698 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1699 }
1700 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1701 rlResult.lowReg, 31);
1702 storeValueWide(cUnit, rlDest, rlResult);
1703 break;
1704
1705 case OP_LONG_TO_INT:
1706 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1707 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1708 storeValue(cUnit, rlDest, rlSrc[0]);
1709 break;
1710
1711 case OP_INT_TO_BYTE:
1712 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1713 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1714 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1715 storeValue(cUnit, rlDest, rlResult);
1716 break;
1717
1718 case OP_INT_TO_SHORT:
1719 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1720 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1721 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1722 storeValue(cUnit, rlDest, rlResult);
1723 break;
1724
1725 case OP_INT_TO_CHAR:
1726 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1727 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1728 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1729 storeValue(cUnit, rlDest, rlResult);
1730 break;
1731
1732 case OP_INT_TO_FLOAT:
1733 case OP_INT_TO_DOUBLE:
1734 case OP_LONG_TO_FLOAT:
1735 case OP_LONG_TO_DOUBLE:
1736 case OP_FLOAT_TO_INT:
1737 case OP_FLOAT_TO_LONG:
1738 case OP_FLOAT_TO_DOUBLE:
1739 case OP_DOUBLE_TO_INT:
1740 case OP_DOUBLE_TO_LONG:
1741 case OP_DOUBLE_TO_FLOAT:
1742 genConversion(cUnit, mir);
1743 break;
1744
1745 case OP_ADD_INT:
1746 case OP_SUB_INT:
1747 case OP_MUL_INT:
1748 case OP_DIV_INT:
1749 case OP_REM_INT:
1750 case OP_AND_INT:
1751 case OP_OR_INT:
1752 case OP_XOR_INT:
1753 case OP_SHL_INT:
1754 case OP_SHR_INT:
1755 case OP_USHR_INT:
1756 case OP_ADD_INT_2ADDR:
1757 case OP_SUB_INT_2ADDR:
1758 case OP_MUL_INT_2ADDR:
1759 case OP_DIV_INT_2ADDR:
1760 case OP_REM_INT_2ADDR:
1761 case OP_AND_INT_2ADDR:
1762 case OP_OR_INT_2ADDR:
1763 case OP_XOR_INT_2ADDR:
1764 case OP_SHL_INT_2ADDR:
1765 case OP_SHR_INT_2ADDR:
1766 case OP_USHR_INT_2ADDR:
1767 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1768 break;
1769
1770 case OP_ADD_LONG:
1771 case OP_SUB_LONG:
1772 case OP_MUL_LONG:
1773 case OP_DIV_LONG:
1774 case OP_REM_LONG:
1775 case OP_AND_LONG:
1776 case OP_OR_LONG:
1777 case OP_XOR_LONG:
1778 case OP_ADD_LONG_2ADDR:
1779 case OP_SUB_LONG_2ADDR:
1780 case OP_MUL_LONG_2ADDR:
1781 case OP_DIV_LONG_2ADDR:
1782 case OP_REM_LONG_2ADDR:
1783 case OP_AND_LONG_2ADDR:
1784 case OP_OR_LONG_2ADDR:
1785 case OP_XOR_LONG_2ADDR:
1786 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1787 break;
1788
buzbee67bf8852011-08-17 17:51:35 -07001789 case OP_SHL_LONG:
1790 case OP_SHR_LONG:
1791 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001792 case OP_SHL_LONG_2ADDR:
1793 case OP_SHR_LONG_2ADDR:
1794 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001795 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1796 break;
1797
1798 case OP_ADD_FLOAT:
1799 case OP_SUB_FLOAT:
1800 case OP_MUL_FLOAT:
1801 case OP_DIV_FLOAT:
1802 case OP_REM_FLOAT:
1803 case OP_ADD_FLOAT_2ADDR:
1804 case OP_SUB_FLOAT_2ADDR:
1805 case OP_MUL_FLOAT_2ADDR:
1806 case OP_DIV_FLOAT_2ADDR:
1807 case OP_REM_FLOAT_2ADDR:
1808 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1809 break;
1810
1811 case OP_ADD_DOUBLE:
1812 case OP_SUB_DOUBLE:
1813 case OP_MUL_DOUBLE:
1814 case OP_DIV_DOUBLE:
1815 case OP_REM_DOUBLE:
1816 case OP_ADD_DOUBLE_2ADDR:
1817 case OP_SUB_DOUBLE_2ADDR:
1818 case OP_MUL_DOUBLE_2ADDR:
1819 case OP_DIV_DOUBLE_2ADDR:
1820 case OP_REM_DOUBLE_2ADDR:
1821 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1822 break;
1823
1824 case OP_RSUB_INT:
1825 case OP_ADD_INT_LIT16:
1826 case OP_MUL_INT_LIT16:
1827 case OP_DIV_INT_LIT16:
1828 case OP_REM_INT_LIT16:
1829 case OP_AND_INT_LIT16:
1830 case OP_OR_INT_LIT16:
1831 case OP_XOR_INT_LIT16:
1832 case OP_ADD_INT_LIT8:
1833 case OP_RSUB_INT_LIT8:
1834 case OP_MUL_INT_LIT8:
1835 case OP_DIV_INT_LIT8:
1836 case OP_REM_INT_LIT8:
1837 case OP_AND_INT_LIT8:
1838 case OP_OR_INT_LIT8:
1839 case OP_XOR_INT_LIT8:
1840 case OP_SHL_INT_LIT8:
1841 case OP_SHR_INT_LIT8:
1842 case OP_USHR_INT_LIT8:
1843 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1844 break;
1845
1846 default:
1847 res = true;
1848 }
1849 return res;
1850}
1851
Elliott Hughesc1f143d2011-12-01 17:31:10 -08001852STATIC const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
buzbee67bf8852011-08-17 17:51:35 -07001853 "kMirOpPhi",
1854 "kMirOpNullNRangeUpCheck",
1855 "kMirOpNullNRangeDownCheck",
1856 "kMirOpLowerBound",
1857 "kMirOpPunt",
1858 "kMirOpCheckInlinePrediction",
1859};
1860
1861/* Extended MIR instructions like PHI */
buzbeeed3e9302011-09-23 17:34:19 -07001862STATIC void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
buzbee67bf8852011-08-17 17:51:35 -07001863{
1864 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1865 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1866 strcpy(msg, extendedMIROpNames[opOffset]);
1867 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1868
1869 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1870 case kMirOpPhi: {
1871 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1872 op->flags.isNop = true;
1873 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1874 break;
1875 }
1876 default:
1877 break;
1878 }
1879}
1880
buzbee67bc2362011-10-11 18:08:40 -07001881/*
1882 * If there are any ins passed in registers that have not been promoted
1883 * to a callee-save register, flush them to the frame. Perform intial
1884 * assignment of promoted arguments.
1885 */
buzbeeed3e9302011-09-23 17:34:19 -07001886STATIC void flushIns(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -07001887{
Ian Rogersa3760aa2011-11-14 14:32:37 -08001888 if (cUnit->numIns == 0)
buzbee67bf8852011-08-17 17:51:35 -07001889 return;
buzbee67bc2362011-10-11 18:08:40 -07001890 int firstArgReg = r1;
1891 int lastArgReg = r3;
Ian Rogersa3760aa2011-11-14 14:32:37 -08001892 int startVReg = cUnit->numDalvikRegisters - cUnit->numIns;
buzbee8febc582011-10-25 12:39:20 -07001893 /*
1894 * Arguments passed in registers should be flushed
1895 * to their backing locations in the frame for now.
1896 * Also, we need to do initial assignment for promoted
1897 * arguments. NOTE: an older version of dx had an issue
1898 * in which it would reuse static method argument registers.
1899 * This could result in the same Dalvik virtual register
1900 * being promoted to both core and fp regs. In those
1901 * cases, copy argument to both. This will be uncommon
1902 * enough that it isn't worth attempting to optimize.
1903 */
Ian Rogersa3760aa2011-11-14 14:32:37 -08001904 for (int i = 0; i < cUnit->numIns; i++) {
buzbee67bc2362011-10-11 18:08:40 -07001905 PromotionMap vMap = cUnit->promotionMap[startVReg + i];
buzbee67bc2362011-10-11 18:08:40 -07001906 if (i <= (lastArgReg - firstArgReg)) {
buzbee8febc582011-10-25 12:39:20 -07001907 // If arriving in register
buzbee67bc2362011-10-11 18:08:40 -07001908 if (vMap.coreLocation == kLocPhysReg) {
1909 genRegCopy(cUnit, vMap.coreReg, firstArgReg + i);
buzbee8febc582011-10-25 12:39:20 -07001910 }
1911 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001912 genRegCopy(cUnit, vMap.fpReg, firstArgReg + i);
1913 }
1914 // Also put a copy in memory in case we're partially promoted
1915 storeBaseDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1916 firstArgReg + i, kWord);
1917 } else {
buzbee8febc582011-10-25 12:39:20 -07001918 // If arriving in frame & promoted
buzbee67bc2362011-10-11 18:08:40 -07001919 if (vMap.coreLocation == kLocPhysReg) {
1920 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1921 vMap.coreReg);
buzbee8febc582011-10-25 12:39:20 -07001922 }
1923 if (vMap.fpLocation == kLocPhysReg) {
buzbee67bc2362011-10-11 18:08:40 -07001924 loadWordDisp(cUnit, rSP, oatSRegOffset(cUnit, startVReg + i),
1925 vMap.fpReg);
buzbee67bf8852011-08-17 17:51:35 -07001926 }
1927 }
buzbee67bf8852011-08-17 17:51:35 -07001928 }
1929}
1930
1931/* Handle the content in each basic block */
buzbeeed3e9302011-09-23 17:34:19 -07001932STATIC bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -07001933{
1934 MIR* mir;
1935 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1936 int blockId = bb->id;
1937
1938 cUnit->curBlock = bb;
1939 labelList[blockId].operands[0] = bb->startOffset;
1940
1941 /* Insert the block label */
1942 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1943 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1944
buzbee6181f792011-09-29 11:14:04 -07001945 /* Reset local optimization data on block boundaries */
1946 oatResetRegPool(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001947 oatClobberAllRegs(cUnit);
buzbee6181f792011-09-29 11:14:04 -07001948 oatResetDefTracking(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001949
1950 ArmLIR* headLIR = NULL;
1951
buzbeebbaf8942011-10-02 13:08:29 -07001952 int spillCount = cUnit->numCoreSpills + cUnit->numFPSpills;
buzbee67bf8852011-08-17 17:51:35 -07001953 if (bb->blockType == kEntryBlock) {
1954 /*
1955 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1956 * mechanism know so it doesn't try to use any of them when
1957 * expanding the frame or flushing. This leaves the utility
1958 * code with a single temp: r12. This should be enough.
1959 */
1960 oatLockTemp(cUnit, r0);
1961 oatLockTemp(cUnit, r1);
1962 oatLockTemp(cUnit, r2);
1963 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001964
1965 /*
1966 * We can safely skip the stack overflow check if we're
1967 * a leaf *and* our frame size < fudge factor.
1968 */
1969 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1970 ((size_t)cUnit->frameSize <
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001971 Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001972 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001973 if (!skipOverflowCheck) {
1974 /* Load stack limit */
1975 loadWordDisp(cUnit, rSELF,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001976 Thread::StackEndOffset().Int32Value(), r12);
buzbeecefd1872011-09-09 09:59:52 -07001977 }
buzbee67bf8852011-08-17 17:51:35 -07001978 /* Spill core callee saves */
1979 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1980 /* Need to spill any FP regs? */
1981 if (cUnit->numFPSpills) {
buzbeebbaf8942011-10-02 13:08:29 -07001982 /*
1983 * NOTE: fp spills are a little different from core spills in that
1984 * they are pushed as a contiguous block. When promoting from
1985 * the fp set, we must allocate all singles from s16..highest-promoted
1986 */
buzbee67bf8852011-08-17 17:51:35 -07001987 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1988 }
buzbeecefd1872011-09-09 09:59:52 -07001989 if (!skipOverflowCheck) {
1990 opRegRegImm(cUnit, kOpSub, rLR, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001991 cUnit->frameSize - (spillCount * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001992 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1993 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001994 genRegCopy(cUnit, rSP, rLR); // Establish stack
1995 } else {
1996 opRegImm(cUnit, kOpSub, rSP,
buzbeebbaf8942011-10-02 13:08:29 -07001997 cUnit->frameSize - (spillCount * 4));
buzbeecefd1872011-09-09 09:59:52 -07001998 }
buzbee67bf8852011-08-17 17:51:35 -07001999 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
2000 flushIns(cUnit);
2001 oatFreeTemp(cUnit, r0);
2002 oatFreeTemp(cUnit, r1);
2003 oatFreeTemp(cUnit, r2);
2004 oatFreeTemp(cUnit, r3);
2005 } else if (bb->blockType == kExitBlock) {
2006 newLIR0(cUnit, kArmPseudoMethodExit);
buzbeebbaf8942011-10-02 13:08:29 -07002007 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (spillCount * 4));
buzbee67bf8852011-08-17 17:51:35 -07002008 /* Need to restore any FP callee saves? */
2009 if (cUnit->numFPSpills) {
2010 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
2011 }
2012 if (cUnit->coreSpillMask & (1 << rLR)) {
2013 /* Unspill rLR to rPC */
2014 cUnit->coreSpillMask &= ~(1 << rLR);
2015 cUnit->coreSpillMask |= (1 << rPC);
2016 }
2017 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
2018 if (!(cUnit->coreSpillMask & (1 << rPC))) {
2019 /* We didn't pop to rPC, so must do a bv rLR */
2020 newLIR1(cUnit, kThumbBx, rLR);
2021 }
2022 }
2023
2024 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
2025
2026 oatResetRegPool(cUnit);
buzbeec0ecd652011-09-25 18:11:54 -07002027 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
2028 oatClobberAllRegs(cUnit);
2029 }
buzbee67bf8852011-08-17 17:51:35 -07002030
2031 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
2032 oatResetDefTracking(cUnit);
2033 }
2034
2035 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
2036 handleExtendedMethodMIR(cUnit, mir);
2037 continue;
2038 }
2039
2040 cUnit->currentDalvikOffset = mir->offset;
2041
2042 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
2043 InstructionFormat dalvikFormat =
2044 dexGetFormatFromOpcode(dalvikOpcode);
2045
2046 ArmLIR* boundaryLIR;
2047
2048 /* Mark the beginning of a Dalvik instruction for line tracking */
2049 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
2050 (int) oatGetDalvikDisassembly(
2051 &mir->dalvikInsn, ""));
2052 /* Remember the first LIR for this block */
2053 if (headLIR == NULL) {
2054 headLIR = boundaryLIR;
2055 /* Set the first boundaryLIR as a scheduling barrier */
2056 headLIR->defMask = ENCODE_ALL;
2057 }
2058
2059 /* Don't generate the SSA annotation unless verbose mode is on */
2060 if (cUnit->printMe && mir->ssaRep) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -08002061 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
buzbee67bf8852011-08-17 17:51:35 -07002062 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
2063 }
2064
2065 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
2066
2067 if (notHandled) {
2068 char buf[100];
2069 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
2070 mir->offset,
2071 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
2072 dalvikFormat);
2073 LOG(FATAL) << buf;
2074 }
2075 }
2076
2077 if (headLIR) {
2078 /*
2079 * Eliminate redundant loads/stores and delay stores into later
2080 * slots
2081 */
2082 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
2083 cUnit->lastLIRInsn);
2084
2085 /*
2086 * Generate an unconditional branch to the fallthrough block.
2087 */
2088 if (bb->fallThrough) {
2089 genUnconditionalBranch(cUnit,
2090 &labelList[bb->fallThrough->id]);
2091 }
2092 }
2093 return false;
2094}
2095
2096/*
2097 * Nop any unconditional branches that go to the next instruction.
2098 * Note: new redundant branches may be inserted later, and we'll
2099 * use a check in final instruction assembly to nop those out.
2100 */
2101void removeRedundantBranches(CompilationUnit* cUnit)
2102{
2103 ArmLIR* thisLIR;
2104
2105 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
2106 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
2107 thisLIR = NEXT_LIR(thisLIR)) {
2108
2109 /* Branch to the next instruction */
2110 if ((thisLIR->opcode == kThumbBUncond) ||
2111 (thisLIR->opcode == kThumb2BUncond)) {
2112 ArmLIR* nextLIR = thisLIR;
2113
2114 while (true) {
2115 nextLIR = NEXT_LIR(nextLIR);
2116
2117 /*
2118 * Is the branch target the next instruction?
2119 */
2120 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
2121 thisLIR->flags.isNop = true;
2122 break;
2123 }
2124
2125 /*
2126 * Found real useful stuff between the branch and the target.
2127 * Need to explicitly check the lastLIRInsn here because it
2128 * might be the last real instruction.
2129 */
2130 if (!isPseudoOpcode(nextLIR->opcode) ||
2131 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
2132 break;
2133 }
2134 }
2135 }
2136}
2137
buzbeeed3e9302011-09-23 17:34:19 -07002138STATIC void handleSuspendLaunchpads(CompilationUnit *cUnit)
buzbeec1f45042011-09-21 16:03:19 -07002139{
2140 ArmLIR** suspendLabel =
2141 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2142 int numElems = cUnit->suspendLaunchpads.numUsed;
2143
2144 for (int i = 0; i < numElems; i++) {
2145 /* TUNING: move suspend count load into helper */
2146 ArmLIR* lab = suspendLabel[i];
2147 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2148 cUnit->currentDalvikOffset = lab->operands[1];
2149 oatAppendLIR(cUnit, (LIR *)lab);
2150 loadWordDisp(cUnit, rSELF,
2151 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2152 loadWordDisp(cUnit, rSELF,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002153 Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
buzbeec1f45042011-09-21 16:03:19 -07002154 opReg(cUnit, kOpBlx, rLR);
2155 genUnconditionalBranch(cUnit, resumeLab);
2156 }
2157}
2158
buzbeeed3e9302011-09-23 17:34:19 -07002159STATIC void handleThrowLaunchpads(CompilationUnit *cUnit)
buzbee5ade1d22011-09-09 14:44:52 -07002160{
2161 ArmLIR** throwLabel =
2162 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2163 int numElems = cUnit->throwLaunchpads.numUsed;
2164 int i;
2165
2166 for (i = 0; i < numElems; i++) {
2167 ArmLIR* lab = throwLabel[i];
2168 cUnit->currentDalvikOffset = lab->operands[1];
2169 oatAppendLIR(cUnit, (LIR *)lab);
2170 int funcOffset = 0;
2171 int v1 = lab->operands[2];
2172 int v2 = lab->operands[3];
2173 switch(lab->operands[0]) {
2174 case kArmThrowNullPointer:
2175 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2176 break;
2177 case kArmThrowArrayBounds:
2178 if (v2 != r0) {
2179 genRegCopy(cUnit, r0, v1);
2180 genRegCopy(cUnit, r1, v2);
2181 } else {
2182 if (v1 == r1) {
2183 genRegCopy(cUnit, r12, v1);
2184 genRegCopy(cUnit, r1, v2);
2185 genRegCopy(cUnit, r0, r12);
2186 } else {
2187 genRegCopy(cUnit, r1, v2);
2188 genRegCopy(cUnit, r0, v1);
2189 }
2190 }
2191 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2192 break;
2193 case kArmThrowDivZero:
2194 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2195 break;
2196 case kArmThrowVerificationError:
2197 loadConstant(cUnit, r0, v1);
2198 loadConstant(cUnit, r1, v2);
2199 funcOffset =
2200 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2201 break;
2202 case kArmThrowNegArraySize:
2203 genRegCopy(cUnit, r0, v1);
2204 funcOffset =
2205 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2206 break;
buzbee5ade1d22011-09-09 14:44:52 -07002207 case kArmThrowNoSuchMethod:
buzbee13ac45a2012-01-12 12:30:16 -08002208 genRegCopy(cUnit, r0, v1);
buzbee5ade1d22011-09-09 14:44:52 -07002209 funcOffset =
2210 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2211 break;
buzbeeec5adf32011-09-11 15:25:43 -07002212 case kArmThrowStackOverflow:
2213 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002214 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002215 // Restore stack alignment
buzbeebbaf8942011-10-02 13:08:29 -07002216 opRegImm(cUnit, kOpAdd, rSP,
2217 (cUnit->numCoreSpills + cUnit->numFPSpills) * 4);
buzbeeec5adf32011-09-11 15:25:43 -07002218 break;
buzbee5ade1d22011-09-09 14:44:52 -07002219 default:
2220 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2221 }
2222 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002223 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002224 }
2225}
2226
buzbee67bf8852011-08-17 17:51:35 -07002227void oatMethodMIR2LIR(CompilationUnit* cUnit)
2228{
2229 /* Used to hold the labels of each block */
2230 cUnit->blockLabelList =
2231 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2232
2233 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2234 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002235 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002236
2237 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002238
2239 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002240}
2241
2242/* Common initialization routine for an architecture family */
2243bool oatArchInit()
2244{
2245 int i;
2246
2247 for (i = 0; i < kArmLast; i++) {
2248 if (EncodingMap[i].opcode != i) {
2249 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2250 " is wrong: expecting " << i << ", seeing " <<
2251 (int)EncodingMap[i].opcode;
2252 }
2253 }
2254
2255 return oatArchVariantInit();
2256}
2257
2258/* Needed by the Assembler */
2259void oatSetupResourceMasks(ArmLIR* lir)
2260{
2261 setupResourceMasks(lir);
2262}
2263
2264/* Needed by the ld/st optmizatons */
2265ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2266{
2267 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2268}
2269
2270/* Needed by the register allocator */
2271ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2272{
2273 return genRegCopy(cUnit, rDest, rSrc);
2274}
2275
2276/* Needed by the register allocator */
2277void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2278 int srcLo, int srcHi)
2279{
2280 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2281}
2282
2283void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2284 int displacement, int rSrc, OpSize size)
2285{
2286 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2287}
2288
2289void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2290 int displacement, int rSrcLo, int rSrcHi)
2291{
2292 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2293}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08002294
2295} // namespace art