blob: f42237a2352933069b4e44407df0626b7197e2b1 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughes1240dad2011-09-09 16:24:50 -070017#define DISPLAY_MISSING_TARGETS 1
18
buzbee67bf8852011-08-17 17:51:35 -070019static const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
20 INVALID_REG, INVALID_SREG, 0,
21 kLocDalvikFrame, INVALID_REG, INVALID_REG,
22 INVALID_OFFSET};
23static const RegLocation retLoc = LOC_DALVIK_RETURN_VAL;
24static const RegLocation retLocWide = LOC_DALVIK_RETURN_VAL_WIDE;
25
buzbeedfd3d702011-08-28 12:56:51 -070026/*
27 * Let helper function take care of everything. Will call
28 * Array::AllocFromCode(type_idx, method, count);
29 * Note: AllocFromCode will handle checks for errNegativeArraySize.
30 */
buzbee67bf8852011-08-17 17:51:35 -070031static void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
32 RegLocation rlSrc)
33{
buzbeedfd3d702011-08-28 12:56:51 -070034 oatFlushAllRegs(cUnit); /* Everything to home location */
35 loadWordDisp(cUnit, rSELF,
36 OFFSETOF_MEMBER(Thread, pAllocFromCode), rLR);
37 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
38 loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
39 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
buzbeeec5adf32011-09-11 15:25:43 -070040 callUnwindableHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070041 oatClobberCallRegs(cUnit);
42 RegLocation rlResult = oatGetReturn(cUnit);
43 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070044}
45
46/*
47 * Similar to genNewArray, but with post-allocation initialization.
48 * Verifier guarantees we're dealing with an array class. Current
49 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
50 * Current code also throws internal unimp if not 'L', '[' or 'I'.
51 */
52static void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
53{
54 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070055 int elems = dInsn->vA;
56 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070057 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070058 loadWordDisp(cUnit, rSELF,
buzbee1da522d2011-09-04 11:22:20 -070059 OFFSETOF_MEMBER(Thread, pCheckAndAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070060 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
61 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
62 loadConstant(cUnit, r2, elems); // arg2 <- count
buzbeeec5adf32011-09-11 15:25:43 -070063 callUnwindableHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070064 /*
buzbeedfd3d702011-08-28 12:56:51 -070065 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
66 * return region. Because AllocFromCode placed the new array
67 * in r0, we'll just lock it into place. When debugger support is
68 * added, it may be necessary to additionally copy all return
69 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070070 */
buzbee67bf8852011-08-17 17:51:35 -070071 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070072
buzbee67bf8852011-08-17 17:51:35 -070073 // Having a range of 0 is legal
74 if (isRange && (dInsn->vA > 0)) {
75 /*
76 * Bit of ugliness here. We're going generate a mem copy loop
77 * on the register range, but it is possible that some regs
78 * in the range have been promoted. This is unlikely, but
79 * before generating the copy, we'll just force a flush
80 * of any regs in the source range that have been promoted to
81 * home location.
82 */
83 for (unsigned int i = 0; i < dInsn->vA; i++) {
84 RegLocation loc = oatUpdateLoc(cUnit,
85 oatGetSrc(cUnit, mir, i));
86 if (loc.location == kLocPhysReg) {
87 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
88 }
89 }
90 /*
91 * TUNING note: generated code here could be much improved, but
92 * this is an uncommon operation and isn't especially performance
93 * critical.
94 */
95 int rSrc = oatAllocTemp(cUnit);
96 int rDst = oatAllocTemp(cUnit);
97 int rIdx = oatAllocTemp(cUnit);
98 int rVal = rLR; // Using a lot of temps, rLR is known free here
99 // Set up source pointer
100 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
101 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
102 // Set up the target pointer
103 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700104 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700105 // Set up the loop counter (known to be > 0)
106 loadConstant(cUnit, rIdx, dInsn->vA);
107 // Generate the copy loop. Going backwards for convenience
108 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
109 target->defMask = ENCODE_ALL;
110 // Copy next element
111 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
112 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
113 // Use setflags encoding here
114 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
115 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
116 branch->generic.target = (LIR*)target;
117 } else if (!isRange) {
118 // TUNING: interleave
119 for (unsigned int i = 0; i < dInsn->vA; i++) {
120 RegLocation rlArg = loadValue(cUnit,
121 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700122 storeBaseDisp(cUnit, r0,
123 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700124 i * 4, rlArg.lowReg, kWord);
125 // If the loadValue caused a temp to be allocated, free it
126 if (oatIsTemp(cUnit, rlArg.lowReg)) {
127 oatFreeTemp(cUnit, rlArg.lowReg);
128 }
129 }
130 }
131}
132
133static void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
134{
buzbeee1931742011-08-28 21:15:53 -0700135 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
136 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700137 int fieldIdx = mir->dalvikInsn.vB;
138 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
139 if (field == NULL) {
140 // Slow path
buzbee34cd9e52011-09-08 14:31:52 -0700141 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
142 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700143 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
144 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700145 oatFlushAllRegs(cUnit);
146 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
147 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
148 loadCurrMethodDirect(cUnit, r1);
149 loadValueDirect(cUnit, rlSrc, r2);
buzbeeec5adf32011-09-11 15:25:43 -0700150 callUnwindableHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700151 oatClobberCallRegs(cUnit);
152 } else {
buzbee1da522d2011-09-04 11:22:20 -0700153 // fast path
154 int fieldOffset = field->GetOffset().Int32Value();
155 art::ClassLinker* class_linker = art::Runtime::Current()->
156 GetClassLinker();
157 const art::DexFile& dex_file = class_linker->
Elliott Hughesb1539062011-09-11 16:14:31 -0700158 FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
buzbee1da522d2011-09-04 11:22:20 -0700159 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
160 int typeIdx = field_id.class_idx_;
161 // Using fixed register to sync with slow path
162 int rMethod = r1;
163 oatLockTemp(cUnit, rMethod);
164 loadCurrMethodDirect(cUnit, rMethod);
165 int rBase = r0;
166 oatLockTemp(cUnit, rBase);
167 loadWordDisp(cUnit, rMethod,
168 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
169 rBase);
170 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
171 sizeof(int32_t*)* typeIdx, rBase);
172 // TUNING: fast path should fall through
173 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
174 loadWordDisp(cUnit, rSELF,
175 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
176 loadConstant(cUnit, r0, typeIdx);
buzbeeec5adf32011-09-11 15:25:43 -0700177 callUnwindableHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700178 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
179 skipTarget->defMask = ENCODE_ALL;
180 branchOver->generic.target = (LIR*)skipTarget;
181 rlSrc = oatGetSrc(cUnit, mir, 0);
182 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
183 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700184#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700185 if (field->IsVolatile()) {
186 oatGenMemBarrier(cUnit, kSY);
187 }
buzbee67bf8852011-08-17 17:51:35 -0700188#endif
buzbee1da522d2011-09-04 11:22:20 -0700189 if (isObject) {
190 markGCCard(cUnit, rlSrc.lowReg, rBase);
191 }
192 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700193 }
buzbee67bf8852011-08-17 17:51:35 -0700194}
195
196static void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
197{
buzbee1da522d2011-09-04 11:22:20 -0700198 int fieldIdx = mir->dalvikInsn.vB;
199 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700200 if (SLOW_FIELD_PATH || field == NULL) {
201 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
202 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700203 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700204 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700205 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
206 loadCurrMethodDirect(cUnit, r1);
207 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
buzbeeec5adf32011-09-11 15:25:43 -0700208 callUnwindableHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700209 oatClobberCallRegs(cUnit);
210 } else {
buzbee1da522d2011-09-04 11:22:20 -0700211 // fast path
212 int fieldOffset = field->GetOffset().Int32Value();
213 art::ClassLinker* class_linker = art::Runtime::Current()->
214 GetClassLinker();
215 const art::DexFile& dex_file = class_linker->
Elliott Hughesb1539062011-09-11 16:14:31 -0700216 FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
buzbee1da522d2011-09-04 11:22:20 -0700217 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
218 int typeIdx = field_id.class_idx_;
219 // Using fixed register to sync with slow path
220 int rMethod = r1;
221 oatLockTemp(cUnit, rMethod);
222 loadCurrMethodDirect(cUnit, r1);
223 int rBase = r0;
224 oatLockTemp(cUnit, rBase);
225 loadWordDisp(cUnit, rMethod,
226 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
227 rBase);
228 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
229 sizeof(int32_t*)* typeIdx, rBase);
230 // TUNING: fast path should fall through
231 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
232 loadWordDisp(cUnit, rSELF,
233 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
234 loadConstant(cUnit, r0, typeIdx);
buzbeeec5adf32011-09-11 15:25:43 -0700235 callUnwindableHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700236 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
237 skipTarget->defMask = ENCODE_ALL;
238 branchOver->generic.target = (LIR*)skipTarget;
239 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
240 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
241 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
242 rlSrc.highReg);
243#if ANDROID_SMP != 0
244 if (field->IsVolatile()) {
245 oatGenMemBarrier(cUnit, kSY);
246 }
buzbeec143c552011-08-20 17:38:58 -0700247#endif
buzbee1da522d2011-09-04 11:22:20 -0700248 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700249 }
buzbee67bf8852011-08-17 17:51:35 -0700250}
251
252
buzbee67bf8852011-08-17 17:51:35 -0700253static void genSgetWide(CompilationUnit* cUnit, MIR* mir,
254 RegLocation rlResult, RegLocation rlDest)
255{
buzbee1da522d2011-09-04 11:22:20 -0700256 int fieldIdx = mir->dalvikInsn.vB;
257 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700258 if (SLOW_FIELD_PATH || field == NULL) {
259 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
260 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700261 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700262 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700263 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
264 loadCurrMethodDirect(cUnit, r1);
buzbeeec5adf32011-09-11 15:25:43 -0700265 callUnwindableHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700266 RegLocation rlResult = oatGetReturnWide(cUnit);
267 storeValueWide(cUnit, rlDest, rlResult);
268 } else {
buzbee1da522d2011-09-04 11:22:20 -0700269 // Fast path
270 int fieldOffset = field->GetOffset().Int32Value();
271 art::ClassLinker* class_linker = art::Runtime::Current()->
272 GetClassLinker();
273 const art::DexFile& dex_file = class_linker->
Elliott Hughesb1539062011-09-11 16:14:31 -0700274 FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
buzbee1da522d2011-09-04 11:22:20 -0700275 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
276 int typeIdx = field_id.class_idx_;
277 // Using fixed register to sync with slow path
278 int rMethod = r1;
279 oatLockTemp(cUnit, rMethod);
280 loadCurrMethodDirect(cUnit, rMethod);
281 int rBase = r0;
282 oatLockTemp(cUnit, rBase);
283 loadWordDisp(cUnit, rMethod,
284 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
285 rBase);
286 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
287 sizeof(int32_t*)* typeIdx, rBase);
288 // TUNING: fast path should fall through
289 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
290 loadWordDisp(cUnit, rSELF,
291 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
292 loadConstant(cUnit, r0, typeIdx);
buzbeeec5adf32011-09-11 15:25:43 -0700293 callUnwindableHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700294 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
295 skipTarget->defMask = ENCODE_ALL;
296 branchOver->generic.target = (LIR*)skipTarget;
297 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
298 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
299#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700300 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700301 oatGenMemBarrier(cUnit, kSY);
302 }
buzbeec143c552011-08-20 17:38:58 -0700303#endif
buzbee1da522d2011-09-04 11:22:20 -0700304 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
305 rlResult.highReg, INVALID_SREG);
306 oatFreeTemp(cUnit, rBase);
307 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700308 }
buzbee67bf8852011-08-17 17:51:35 -0700309}
310
311static void genSget(CompilationUnit* cUnit, MIR* mir,
312 RegLocation rlResult, RegLocation rlDest)
313{
buzbee1da522d2011-09-04 11:22:20 -0700314 int fieldIdx = mir->dalvikInsn.vB;
315 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee1931742011-08-28 21:15:53 -0700316 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
317 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee34cd9e52011-09-08 14:31:52 -0700318 if (SLOW_FIELD_PATH || field == NULL) {
319 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
320 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700321 // Slow path
322 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
323 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700324 oatFlushAllRegs(cUnit);
325 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
326 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
327 loadCurrMethodDirect(cUnit, r1);
buzbeeec5adf32011-09-11 15:25:43 -0700328 callUnwindableHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700329 RegLocation rlResult = oatGetReturn(cUnit);
330 storeValue(cUnit, rlDest, rlResult);
331 } else {
buzbee1da522d2011-09-04 11:22:20 -0700332 // Fast path
333 int fieldOffset = field->GetOffset().Int32Value();
334 art::ClassLinker* class_linker = art::Runtime::Current()->
335 GetClassLinker();
336 const art::DexFile& dex_file = class_linker->
Elliott Hughesb1539062011-09-11 16:14:31 -0700337 FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
buzbee1da522d2011-09-04 11:22:20 -0700338 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
339 int typeIdx = field_id.class_idx_;
340 // Using fixed register to sync with slow path
341 int rMethod = r1;
342 oatLockTemp(cUnit, rMethod);
343 loadCurrMethodDirect(cUnit, rMethod);
344 int rBase = r0;
345 oatLockTemp(cUnit, rBase);
346 loadWordDisp(cUnit, rMethod,
347 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
348 rBase);
349 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
350 sizeof(int32_t*)* typeIdx, rBase);
351 // TUNING: fast path should fall through
352 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
353 loadWordDisp(cUnit, rSELF,
354 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
355 loadConstant(cUnit, r0, typeIdx);
buzbeeec5adf32011-09-11 15:25:43 -0700356 callUnwindableHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700357 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
358 skipTarget->defMask = ENCODE_ALL;
359 branchOver->generic.target = (LIR*)skipTarget;
360 rlDest = oatGetDest(cUnit, mir, 0);
361 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700362#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700363 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700364 oatGenMemBarrier(cUnit, kSY);
365 }
buzbee67bf8852011-08-17 17:51:35 -0700366#endif
buzbee1da522d2011-09-04 11:22:20 -0700367 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
368 oatFreeTemp(cUnit, rBase);
369 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700370 }
buzbee67bf8852011-08-17 17:51:35 -0700371}
372
buzbee561227c2011-09-02 15:28:19 -0700373typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
374 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700375
376/*
377 * Bit of a hack here - in leiu of a real scheduling pass,
378 * emit the next instruction in static & direct invoke sequences.
379 */
380static int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700381 DecodedInstruction* dInsn, int state,
382 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700383{
buzbee561227c2011-09-02 15:28:19 -0700384 DCHECK(rollback == NULL);
385 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700386 switch(state) {
387 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700388 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700389 break;
buzbee561227c2011-09-02 15:28:19 -0700390 case 1: // Get method->code_and_direct_methods_
391 loadWordDisp(cUnit, r0,
392 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
393 r0);
buzbee67bf8852011-08-17 17:51:35 -0700394 break;
buzbee561227c2011-09-02 15:28:19 -0700395 case 2: // Grab target method* and target code_
396 loadWordDisp(cUnit, r0,
397 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
398 loadWordDisp(cUnit, r0,
399 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700400 break;
401 default:
402 return -1;
403 }
404 return state + 1;
405}
406
buzbee67bf8852011-08-17 17:51:35 -0700407/*
408 * Bit of a hack here - in leiu of a real scheduling pass,
409 * emit the next instruction in a virtual invoke sequence.
410 * We can use rLR as a temp prior to target address loading
411 * Note also that we'll load the first argument ("this") into
412 * r1 here rather than the standard loadArgRegs.
413 */
414static int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700415 DecodedInstruction* dInsn, int state,
416 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700417{
buzbee561227c2011-09-02 15:28:19 -0700418 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700419 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700420 /*
421 * This is the fast path in which the target virtual method is
422 * fully resolved at compile time.
423 */
424 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
425 Get(dInsn->vB);
426 CHECK(baseMethod != NULL);
427 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700428 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700429 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700430 rlArg = oatGetSrc(cUnit, mir, 0);
431 loadValueDirectFixed(cUnit, rlArg, r1);
432 break;
buzbee561227c2011-09-02 15:28:19 -0700433 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700434 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700435 // get this->klass_ [use r1, set rLR]
436 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700437 break;
buzbee561227c2011-09-02 15:28:19 -0700438 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
439 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700440 break;
buzbee561227c2011-09-02 15:28:19 -0700441 case 3: // Get target method [use rLR, set r0]
442 loadWordDisp(cUnit, rLR, (target_idx * 4) +
443 art::Array::DataOffset().Int32Value(), r0);
444 break;
445 case 4: // Get the target compiled code address [uses r0, sets rLR]
446 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700447 break;
448 default:
449 return -1;
450 }
451 return state + 1;
452}
453
buzbee7b1b86d2011-08-26 18:59:10 -0700454static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700455 DecodedInstruction* dInsn, int state,
456 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700457{
buzbee561227c2011-09-02 15:28:19 -0700458 DCHECK(rollback != NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700459 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700460 ArmLIR* skipBranch;
461 ArmLIR* skipTarget;
462 /*
463 * This handles the case in which the base method is not fully
464 * resolved at compile time. We must generate code to test
465 * for resolution a run time, bail to the slow path if not to
466 * fill in all the tables. In the latter case, we'll restart at
467 * at the beginning of the sequence.
468 */
buzbee7b1b86d2011-08-26 18:59:10 -0700469 switch(state) {
470 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700471 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700472 break;
buzbee561227c2011-09-02 15:28:19 -0700473 case 1: // Get method->dex_cache_resolved_methods_
474 loadWordDisp(cUnit, r0,
475 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700476 break;
buzbee561227c2011-09-02 15:28:19 -0700477 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
478 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
479 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700480 break;
buzbee561227c2011-09-02 15:28:19 -0700481 case 3: // Resolved?
482 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
483 // Slowest path, bail to helper, rollback and retry
484 loadWordDisp(cUnit, rSELF,
485 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
486 loadConstant(cUnit, r1, dInsn->vB);
buzbeeec5adf32011-09-11 15:25:43 -0700487 callUnwindableHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700488 genUnconditionalBranch(cUnit, rollback);
489 // Resume normal slow path
490 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
491 skipTarget->defMask = ENCODE_ALL;
492 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700493 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700494 loadBaseDisp(cUnit, mir, rLR,
495 Method::GetMethodIndexOffset().Int32Value(), r0,
496 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700497 // Load "this" [set r1]
498 rlArg = oatGetSrc(cUnit, mir, 0);
499 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700500 break;
501 case 4:
502 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700503 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700504 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700505 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700506 break;
buzbee561227c2011-09-02 15:28:19 -0700507 case 5:
508 // get this->klass_->vtable_ [usr rLR, set rLR]
509 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
510 DCHECK((art::Array::DataOffset().Int32Value() & 0x3) == 0);
511 // In load shadow fold vtable_ object header size into method_index_
512 opRegImm(cUnit, kOpAdd, r0,
513 art::Array::DataOffset().Int32Value() / 4);
514 // Get target Method*
515 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
516 break;
517 case 6: // Get the target compiled code address [uses r0, sets rLR]
518 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700519 break;
520 default:
521 return -1;
522 }
523 return state + 1;
524}
525
buzbee67bf8852011-08-17 17:51:35 -0700526/* Load up to 3 arguments in r1..r3 */
527static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
528 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700529 int *args, NextCallInsn nextCallInsn, ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700530{
531 for (int i = 0; i < 3; i++) {
532 if (args[i] != INVALID_REG) {
buzbee1b4c8592011-08-31 10:43:51 -0700533 // Arguments are treated as a series of untyped 32-bit values.
buzbeee9a72f62011-09-04 17:59:07 -0700534 RegLocation rlArg = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700535 rlArg.wide = false;
buzbee67bf8852011-08-17 17:51:35 -0700536 loadValueDirectFixed(cUnit, rlArg, r1 + i);
buzbee561227c2011-09-02 15:28:19 -0700537 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700538 }
539 }
540 return callState;
541}
542
buzbee4a3164f2011-09-03 11:25:10 -0700543// Interleave launch code for INVOKE_INTERFACE.
buzbee67bf8852011-08-17 17:51:35 -0700544static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700545 DecodedInstruction* dInsn, int state,
546 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700547{
buzbee67bf8852011-08-17 17:51:35 -0700548 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700549 case 0: // Load trampoline target
550 loadWordDisp(cUnit, rSELF,
551 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
552 rLR);
553 // Load r0 with method index
554 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700555 break;
buzbee67bf8852011-08-17 17:51:35 -0700556 default:
557 return -1;
558 }
559 return state + 1;
560}
561
buzbee67bf8852011-08-17 17:51:35 -0700562/*
563 * Interleave launch code for INVOKE_SUPER. See comments
564 * for nextVCallIns.
565 */
566static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700567 DecodedInstruction* dInsn, int state,
568 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700569{
buzbee4a3164f2011-09-03 11:25:10 -0700570 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700571 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700572 /*
573 * This is the fast path in which the target virtual method is
574 * fully resolved at compile time. Note also that this path assumes
575 * that the check to verify that the target method index falls
576 * within the size of the super's vtable has been done at compile-time.
577 */
578 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
579 Get(dInsn->vB);
580 CHECK(baseMethod != NULL);
581 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
582 CHECK(superClass != NULL);
583 int32_t target_idx = baseMethod->GetMethodIndex();
584 CHECK(superClass->GetVTable()->GetLength() > target_idx);
585 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
586 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700587 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700588 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700589 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700590 // Load "this" [set r1]
591 rlArg = oatGetSrc(cUnit, mir, 0);
592 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700593 // Get method->declaring_class_ [use r0, set rLR]
594 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
595 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700596 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700597 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700598 break;
599 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
600 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
601 rLR);
602 break;
603 case 2: // Get ...->super_class_->vtable [u/s rLR]
604 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
605 break;
606 case 3: // Get target method [use rLR, set r0]
607 loadWordDisp(cUnit, rLR, (target_idx * 4) +
608 art::Array::DataOffset().Int32Value(), r0);
609 break;
610 case 4: // Get the target compiled code address [uses r0, sets rLR]
611 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
612 break;
buzbee67bf8852011-08-17 17:51:35 -0700613 default:
614 return -1;
615 }
buzbee4a3164f2011-09-03 11:25:10 -0700616 return state + 1;
617}
618
619/* Slow-path version of nextSuperCallInsn */
620static int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
621 DecodedInstruction* dInsn, int state,
622 ArmLIR* rollback)
623{
624 DCHECK(rollback != NULL);
625 RegLocation rlArg;
626 ArmLIR* skipBranch;
627 ArmLIR* skipTarget;
628 int tReg;
629 /*
630 * This handles the case in which the base method is not fully
631 * resolved at compile time. We must generate code to test
632 * for resolution a run time, bail to the slow path if not to
633 * fill in all the tables. In the latter case, we'll restart at
634 * at the beginning of the sequence.
635 */
636 switch(state) {
637 case 0: // Get the current Method* [sets r0]
638 loadCurrMethodDirect(cUnit, r0);
639 break;
640 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
641 loadWordDisp(cUnit, r0,
642 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
643 break;
644 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
645 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
646 art::Array::DataOffset().Int32Value(), rLR);
647 break;
648 case 3: // Resolved?
649 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
650 // Slowest path, bail to helper, rollback and retry
651 loadWordDisp(cUnit, rSELF,
652 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
653 loadConstant(cUnit, r1, dInsn->vB);
buzbeeec5adf32011-09-11 15:25:43 -0700654 callUnwindableHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700655 genUnconditionalBranch(cUnit, rollback);
656 // Resume normal slow path
657 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
658 skipTarget->defMask = ENCODE_ALL;
659 skipBranch->generic.target = (LIR*)skipTarget;
660 // Get base_method->method_index [usr rLR, set rLR]
661 loadBaseDisp(cUnit, mir, rLR,
662 Method::GetMethodIndexOffset().Int32Value(), rLR,
663 kUnsignedHalf, INVALID_SREG);
664 // Load "this" [set r1]
665 rlArg = oatGetSrc(cUnit, mir, 0);
666 loadValueDirectFixed(cUnit, rlArg, r1);
667 // Load curMethod->declaring_class_ [uses r0, sets r0]
668 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
669 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700670 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700671 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700672 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700673 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
674 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700675 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700676 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700677 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700678 // Range check, throw NSM on failure
679 tReg = oatAllocTemp(cUnit);
680 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
681 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700682 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
683 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700684 oatFreeTemp(cUnit, tReg);
685 }
buzbee6a0f7f52011-09-05 16:14:20 -0700686 // Adjust vtable_ base past object header
687 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700688 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700689 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700690 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700691 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700692 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
693 break;
694 default:
695 return -1;
696 }
buzbee67bf8852011-08-17 17:51:35 -0700697 return state + 1;
698}
699
700/*
701 * Load up to 5 arguments, the first three of which will be in
702 * r1 .. r3. On entry r0 contains the current method pointer,
703 * and as part of the load sequence, it must be replaced with
704 * the target method pointer. Note, this may also be called
705 * for "range" variants if the number of arguments is 5 or fewer.
706 */
707static int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
708 DecodedInstruction* dInsn, int callState,
709 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700710 NextCallInsn nextCallInsn, ArmLIR* rollback,
711 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700712{
713 RegLocation rlArg;
714 int registerArgs[3];
715
716 /* If no arguments, just return */
717 if (dInsn->vA == 0)
718 return callState;
719
buzbee561227c2011-09-02 15:28:19 -0700720 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700721
722 /*
723 * Load frame arguments arg4 & arg5 first. Coded a little odd to
724 * pre-schedule the method pointer target.
725 */
726 for (unsigned int i=3; i < dInsn->vA; i++) {
727 int reg;
buzbeeec5adf32011-09-11 15:25:43 -0700728 // Treating args as untyped 32-bit chunks
729 rlArg = oatGetRawSrc(cUnit, mir, i);
730 rlArg.wide = false;
731 rlArg = oatUpdateLoc(cUnit, rlArg);
buzbee67bf8852011-08-17 17:51:35 -0700732 if (rlArg.location == kLocPhysReg) {
733 reg = rlArg.lowReg;
734 } else {
buzbee109bd6a2011-09-06 13:58:41 -0700735 // r3 is the last arg register loaded, so can safely be used here
736 reg = r3;
737 loadValueDirectFixed(cUnit, rlArg, reg);
buzbee561227c2011-09-02 15:28:19 -0700738 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700739 }
740 storeBaseDisp(cUnit, rSP, (i + 1) * 4, reg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700741 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700742 }
743
744 /* Load register arguments r1..r3 */
buzbeee9a72f62011-09-04 17:59:07 -0700745 for (unsigned int i = 0; i < 3; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700746 if (i < dInsn->vA)
747 registerArgs[i] = (isRange) ? dInsn->vC + i : i;
748 else
749 registerArgs[i] = INVALID_REG;
750 }
buzbeee9a72f62011-09-04 17:59:07 -0700751 if (skipThis) {
752 registerArgs[0] = INVALID_REG;
753 }
buzbee67bf8852011-08-17 17:51:35 -0700754 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
buzbee561227c2011-09-02 15:28:19 -0700755 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700756
buzbee6a0f7f52011-09-05 16:14:20 -0700757 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700758 // Load direct & need a "this" null check?
759 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700760 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700761 }
762 return callState;
763}
764
765/*
766 * May have 0+ arguments (also used for jumbo). Note that
767 * source virtual registers may be in physical registers, so may
768 * need to be flushed to home location before copying. This
769 * applies to arg3 and above (see below).
770 *
771 * Two general strategies:
772 * If < 20 arguments
773 * Pass args 3-18 using vldm/vstm block copy
774 * Pass arg0, arg1 & arg2 in r1-r3
775 * If 20+ arguments
776 * Pass args arg19+ using memcpy block copy
777 * Pass arg0, arg1 & arg2 in r1-r3
778 *
779 */
780static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
781 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700782 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700783 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700784{
785 int firstArg = dInsn->vC;
786 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700787 int registerArgs[3];
788
buzbee67bf8852011-08-17 17:51:35 -0700789 // If we can treat it as non-range (Jumbo ops will use range form)
790 if (numArgs <= 5)
791 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700792 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700793 /*
794 * Make sure range list doesn't span the break between in normal
795 * Dalvik vRegs and the ins.
796 */
buzbee1b4c8592011-08-31 10:43:51 -0700797 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700798 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700799 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
800 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700801 }
802
803 /*
804 * First load the non-register arguments. Both forms expect all
805 * of the source arguments to be in their home frame location, so
806 * scan the sReg names and flush any that have been promoted to
807 * frame backing storage.
808 */
809 // Scan the rest of the args - if in physReg flush to memory
buzbee0c7f26d2011-09-07 12:28:51 -0700810 for (int i = 3; i < numArgs; i++) {
buzbeee9a72f62011-09-04 17:59:07 -0700811 RegLocation loc = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700812 if (loc.wide) {
813 loc = oatUpdateLocWide(cUnit, loc);
814 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
815 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
816 loc.highReg);
buzbee561227c2011-09-02 15:28:19 -0700817 callState = nextCallInsn(cUnit, mir, dInsn, callState,
818 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700819 }
820 } else {
821 loc = oatUpdateLoc(cUnit, loc);
822 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
823 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700824 callState = nextCallInsn(cUnit, mir, dInsn, callState,
825 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700826 }
buzbee67bf8852011-08-17 17:51:35 -0700827 }
828 }
829
830 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
831 int outsOffset = 4 /* Method* */ + (3 * 4);
832 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700833 // Generate memcpy
834 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
835 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700836 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
837 loadConstant(cUnit, r2, (numArgs - 3) * 4);
buzbeeec5adf32011-09-11 15:25:43 -0700838 callNoUnwindHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700839 } else {
840 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700841 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700842 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700843 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700844 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
845 //TUNING: loosen barrier
846 ld->defMask = ENCODE_ALL;
847 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700848 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700849 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700850 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700851 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
852 setMemRefType(st, false /* isLoad */, kDalvikReg);
853 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700854 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700855 }
856
857 // Handle the 1st 3 in r1, r2 & r3
buzbeee9a72f62011-09-04 17:59:07 -0700858 for (unsigned int i = 0; i < 3; i++) {
859 if (i < dInsn->vA)
860 registerArgs[i] = dInsn->vC + i;
861 else
862 registerArgs[i] = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700863 }
buzbeee9a72f62011-09-04 17:59:07 -0700864 if (skipThis) {
865 registerArgs[0] = INVALID_REG;
866 }
867 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
868 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700869
buzbee561227c2011-09-02 15:28:19 -0700870 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700871 return callState;
872}
873
buzbee2a475e72011-09-07 17:19:17 -0700874#ifdef DISPLAY_MISSING_TARGETS
875// Debugging routine - if null target, branch to DebugMe
876static void genShowTarget(CompilationUnit* cUnit)
877{
878 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
879 loadWordDisp(cUnit, rSELF,
880 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
881 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
882 target->defMask = -1;
883 branchOver->generic.target = (LIR*)target;
884}
885#endif
886
buzbee561227c2011-09-02 15:28:19 -0700887static void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
888 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700889{
890 DecodedInstruction* dInsn = &mir->dalvikInsn;
891 int callState = 0;
892 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700893 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700894 NextCallInsn nextCallInsn = nextSDCallInsn;
895
buzbee109bd6a2011-09-06 13:58:41 -0700896 // Explicit register usage
897 oatLockCallTemps(cUnit);
898
buzbee561227c2011-09-02 15:28:19 -0700899 if (range) {
900 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700901 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700902 } else {
903 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700904 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700905 }
buzbee67bf8852011-08-17 17:51:35 -0700906 // Finish up any of the call sequence not interleaved in arg loading
907 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700908 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700909 }
buzbee2a475e72011-09-07 17:19:17 -0700910#ifdef DISPLAY_MISSING_TARGETS
911 genShowTarget(cUnit);
912#endif
buzbeeec5adf32011-09-11 15:25:43 -0700913 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700914}
915
buzbee4a3164f2011-09-03 11:25:10 -0700916/*
917 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
918 * which will locate the target and continue on via a tail call.
919 */
buzbee67bf8852011-08-17 17:51:35 -0700920static void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
921{
922 DecodedInstruction* dInsn = &mir->dalvikInsn;
923 int callState = 0;
924 ArmLIR* nullCk;
buzbee109bd6a2011-09-06 13:58:41 -0700925
926 // Explicit register usage
927 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700928 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700929 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700930 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
931 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700932 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -0700933 false);
buzbee67bf8852011-08-17 17:51:35 -0700934 else
935 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -0700936 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -0700937 // Finish up any of the call sequence not interleaved in arg loading
938 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700939 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700940 }
buzbee2a475e72011-09-07 17:19:17 -0700941#ifdef DISPLAY_MISSING_TARGETS
942 genShowTarget(cUnit);
943#endif
buzbeeec5adf32011-09-11 15:25:43 -0700944 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700945}
946
947static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
948{
949 DecodedInstruction* dInsn = &mir->dalvikInsn;
950 int callState = 0;
951 ArmLIR* nullCk;
buzbee4a3164f2011-09-03 11:25:10 -0700952 ArmLIR* rollback;
953 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
954 Get(dInsn->vB);
955 NextCallInsn nextCallInsn;
956 bool fastPath = true;
buzbee109bd6a2011-09-06 13:58:41 -0700957
958 // Explicit register usage
959 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700960 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -0700961 fastPath = false;
962 } else {
963 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
964 if (superClass == NULL) {
965 fastPath = false;
966 } else {
967 int32_t target_idx = baseMethod->GetMethodIndex();
968 if (superClass->GetVTable()->GetLength() <= target_idx) {
969 fastPath = false;
970 } else {
971 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
972 }
973 }
974 }
975 if (fastPath) {
976 nextCallInsn = nextSuperCallInsn;
977 rollback = NULL;
978 } else {
979 nextCallInsn = nextSuperCallInsnSP;
980 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
981 rollback->defMask = -1;
982 }
buzbee67bf8852011-08-17 17:51:35 -0700983 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
984 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700985 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700986 else
987 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700988 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700989 // Finish up any of the call sequence not interleaved in arg loading
990 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -0700991 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700992 }
buzbee2a475e72011-09-07 17:19:17 -0700993#ifdef DISPLAY_MISSING_TARGETS
994 genShowTarget(cUnit);
995#endif
buzbeeec5adf32011-09-11 15:25:43 -0700996 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700997}
998
999static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
1000{
1001 DecodedInstruction* dInsn = &mir->dalvikInsn;
1002 int callState = 0;
1003 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -07001004 ArmLIR* rollback;
1005 Method* method = cUnit->method->GetDexCacheResolvedMethods()->
1006 Get(dInsn->vB);
1007 NextCallInsn nextCallInsn;
buzbee7b1b86d2011-08-26 18:59:10 -07001008
buzbee109bd6a2011-09-06 13:58:41 -07001009 // Explicit register usage
1010 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001011 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001012 // Slow path
1013 nextCallInsn = nextVCallInsnSP;
1014 // If we need a slow-path callout, we'll restart here
1015 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1016 rollback->defMask = -1;
1017 } else {
1018 // Fast path
1019 nextCallInsn = nextVCallInsn;
1020 rollback = NULL;
1021 }
buzbee67bf8852011-08-17 17:51:35 -07001022 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
1023 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001024 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001025 else
1026 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001027 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001028 // Finish up any of the call sequence not interleaved in arg loading
1029 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001030 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001031 }
buzbee2a475e72011-09-07 17:19:17 -07001032#ifdef DISPLAY_MISSING_TARGETS
1033 genShowTarget(cUnit);
1034#endif
buzbeeec5adf32011-09-11 15:25:43 -07001035 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001036}
1037
buzbee67bf8852011-08-17 17:51:35 -07001038static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
1039 BasicBlock* bb, ArmLIR* labelList)
1040{
1041 bool res = false; // Assume success
1042 RegLocation rlSrc[3];
1043 RegLocation rlDest = badLoc;
1044 RegLocation rlResult = badLoc;
1045 Opcode opcode = mir->dalvikInsn.opcode;
1046
1047 /* Prep Src and Dest locations */
1048 int nextSreg = 0;
1049 int nextLoc = 0;
1050 int attrs = oatDataFlowAttributes[opcode];
1051 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1052 if (attrs & DF_UA) {
1053 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1054 nextSreg++;
1055 } else if (attrs & DF_UA_WIDE) {
1056 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1057 nextSreg + 1);
1058 nextSreg+= 2;
1059 }
1060 if (attrs & DF_UB) {
1061 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1062 nextSreg++;
1063 } else if (attrs & DF_UB_WIDE) {
1064 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1065 nextSreg + 1);
1066 nextSreg+= 2;
1067 }
1068 if (attrs & DF_UC) {
1069 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1070 } else if (attrs & DF_UC_WIDE) {
1071 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1072 nextSreg + 1);
1073 }
1074 if (attrs & DF_DA) {
1075 rlDest = oatGetDest(cUnit, mir, 0);
1076 } else if (attrs & DF_DA_WIDE) {
1077 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1078 }
1079
1080 switch(opcode) {
1081 case OP_NOP:
1082 break;
1083
1084 case OP_MOVE_EXCEPTION:
1085 int exOffset;
1086 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001087 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001088 resetReg = oatAllocTemp(cUnit);
1089 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1090 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1091 loadConstant(cUnit, resetReg, 0);
1092 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1093 storeValue(cUnit, rlDest, rlResult);
1094 break;
1095
1096 case OP_RETURN_VOID:
1097 break;
1098
1099 case OP_RETURN:
1100 case OP_RETURN_OBJECT:
1101 storeValue(cUnit, retLoc, rlSrc[0]);
1102 break;
1103
1104 case OP_RETURN_WIDE:
1105 rlDest = retLocWide;
1106 rlDest.fp = rlSrc[0].fp;
1107 storeValueWide(cUnit, rlDest, rlSrc[0]);
1108 break;
1109
1110 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001111 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001112 break; // Nop - combined w/ previous invoke
1113 /*
1114 * Somewhat hacky here. Because we're now passing
1115 * return values in registers, we have to let the
1116 * register allocation utilities know that the return
1117 * registers are live and may not be used for address
1118 * formation in storeValueWide.
1119 */
1120 assert(retLocWide.lowReg == r0);
buzbee1da522d2011-09-04 11:22:20 -07001121 assert(retLocWide.highReg == r1);
buzbee67bf8852011-08-17 17:51:35 -07001122 oatLockTemp(cUnit, retLocWide.lowReg);
1123 oatLockTemp(cUnit, retLocWide.highReg);
1124 storeValueWide(cUnit, rlDest, retLocWide);
1125 oatFreeTemp(cUnit, retLocWide.lowReg);
1126 oatFreeTemp(cUnit, retLocWide.highReg);
1127 break;
1128
1129 case OP_MOVE_RESULT:
1130 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001131 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001132 break; // Nop - combined w/ previous invoke
1133 /* See comment for OP_MOVE_RESULT_WIDE */
1134 assert(retLoc.lowReg == r0);
1135 oatLockTemp(cUnit, retLoc.lowReg);
1136 storeValue(cUnit, rlDest, retLoc);
1137 oatFreeTemp(cUnit, retLoc.lowReg);
1138 break;
1139
1140 case OP_MOVE:
1141 case OP_MOVE_OBJECT:
1142 case OP_MOVE_16:
1143 case OP_MOVE_OBJECT_16:
1144 case OP_MOVE_FROM16:
1145 case OP_MOVE_OBJECT_FROM16:
1146 storeValue(cUnit, rlDest, rlSrc[0]);
1147 break;
1148
1149 case OP_MOVE_WIDE:
1150 case OP_MOVE_WIDE_16:
1151 case OP_MOVE_WIDE_FROM16:
1152 storeValueWide(cUnit, rlDest, rlSrc[0]);
1153 break;
1154
1155 case OP_CONST:
1156 case OP_CONST_4:
1157 case OP_CONST_16:
1158 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1159 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1160 storeValue(cUnit, rlDest, rlResult);
1161 break;
1162
1163 case OP_CONST_HIGH16:
1164 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1165 loadConstantNoClobber(cUnit, rlResult.lowReg,
1166 mir->dalvikInsn.vB << 16);
1167 storeValue(cUnit, rlDest, rlResult);
1168 break;
1169
1170 case OP_CONST_WIDE_16:
1171 case OP_CONST_WIDE_32:
1172 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1173 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1174 //TUNING: do high separately to avoid load dependency
1175 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1176 storeValueWide(cUnit, rlDest, rlResult);
1177 break;
1178
1179 case OP_CONST_WIDE:
1180 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1181 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001182 mir->dalvikInsn.vB_wide & 0xffffffff,
1183 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001184 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001185 break;
1186
1187 case OP_CONST_WIDE_HIGH16:
1188 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1189 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1190 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001191 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001192 break;
1193
1194 case OP_MONITOR_ENTER:
1195 genMonitorEnter(cUnit, mir, rlSrc[0]);
1196 break;
1197
1198 case OP_MONITOR_EXIT:
1199 genMonitorExit(cUnit, mir, rlSrc[0]);
1200 break;
1201
1202 case OP_CHECK_CAST:
1203 genCheckCast(cUnit, mir, rlSrc[0]);
1204 break;
1205
1206 case OP_INSTANCE_OF:
1207 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1208 break;
1209
1210 case OP_NEW_INSTANCE:
1211 genNewInstance(cUnit, mir, rlDest);
1212 break;
1213
1214 case OP_THROW:
1215 genThrow(cUnit, mir, rlSrc[0]);
1216 break;
1217
buzbee5ade1d22011-09-09 14:44:52 -07001218 case OP_THROW_VERIFICATION_ERROR:
1219 loadWordDisp(cUnit, rSELF,
1220 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1221 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1222 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
buzbeeec5adf32011-09-11 15:25:43 -07001223 callUnwindableHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001224 break;
1225
buzbee67bf8852011-08-17 17:51:35 -07001226 case OP_ARRAY_LENGTH:
1227 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001228 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001229 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001230 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001231 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1232 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1233 rlResult.lowReg);
1234 storeValue(cUnit, rlDest, rlResult);
1235 break;
1236
1237 case OP_CONST_STRING:
1238 case OP_CONST_STRING_JUMBO:
1239 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1240 break;
1241
1242 case OP_CONST_CLASS:
1243 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1244 break;
1245
1246 case OP_FILL_ARRAY_DATA:
1247 genFillArrayData(cUnit, mir, rlSrc[0]);
1248 break;
1249
1250 case OP_FILLED_NEW_ARRAY:
1251 genFilledNewArray(cUnit, mir, false /* not range */);
1252 break;
1253
1254 case OP_FILLED_NEW_ARRAY_RANGE:
1255 genFilledNewArray(cUnit, mir, true /* range */);
1256 break;
1257
1258 case OP_NEW_ARRAY:
1259 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1260 break;
1261
1262 case OP_GOTO:
1263 case OP_GOTO_16:
1264 case OP_GOTO_32:
1265 // TUNING: add MIR flag to disable when unnecessary
1266 bool backwardBranch;
1267 backwardBranch = (bb->taken->startOffset <= mir->offset);
1268 if (backwardBranch) {
1269 genSuspendPoll(cUnit, mir);
1270 }
1271 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1272 break;
1273
1274 case OP_PACKED_SWITCH:
1275 genPackedSwitch(cUnit, mir, rlSrc[0]);
1276 break;
1277
1278 case OP_SPARSE_SWITCH:
1279 genSparseSwitch(cUnit, mir, rlSrc[0]);
1280 break;
1281
1282 case OP_CMPL_FLOAT:
1283 case OP_CMPG_FLOAT:
1284 case OP_CMPL_DOUBLE:
1285 case OP_CMPG_DOUBLE:
1286 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1287 break;
1288
1289 case OP_CMP_LONG:
1290 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1291 break;
1292
1293 case OP_IF_EQ:
1294 case OP_IF_NE:
1295 case OP_IF_LT:
1296 case OP_IF_GE:
1297 case OP_IF_GT:
1298 case OP_IF_LE: {
1299 bool backwardBranch;
1300 ArmConditionCode cond;
1301 backwardBranch = (bb->taken->startOffset <= mir->offset);
1302 if (backwardBranch) {
1303 genSuspendPoll(cUnit, mir);
1304 }
1305 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1306 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1307 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1308 switch(opcode) {
1309 case OP_IF_EQ:
1310 cond = kArmCondEq;
1311 break;
1312 case OP_IF_NE:
1313 cond = kArmCondNe;
1314 break;
1315 case OP_IF_LT:
1316 cond = kArmCondLt;
1317 break;
1318 case OP_IF_GE:
1319 cond = kArmCondGe;
1320 break;
1321 case OP_IF_GT:
1322 cond = kArmCondGt;
1323 break;
1324 case OP_IF_LE:
1325 cond = kArmCondLe;
1326 break;
1327 default:
1328 cond = (ArmConditionCode)0;
1329 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1330 }
1331 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1332 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1333 break;
1334 }
1335
1336 case OP_IF_EQZ:
1337 case OP_IF_NEZ:
1338 case OP_IF_LTZ:
1339 case OP_IF_GEZ:
1340 case OP_IF_GTZ:
1341 case OP_IF_LEZ: {
1342 bool backwardBranch;
1343 ArmConditionCode cond;
1344 backwardBranch = (bb->taken->startOffset <= mir->offset);
1345 if (backwardBranch) {
1346 genSuspendPoll(cUnit, mir);
1347 }
1348 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1349 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1350 switch(opcode) {
1351 case OP_IF_EQZ:
1352 cond = kArmCondEq;
1353 break;
1354 case OP_IF_NEZ:
1355 cond = kArmCondNe;
1356 break;
1357 case OP_IF_LTZ:
1358 cond = kArmCondLt;
1359 break;
1360 case OP_IF_GEZ:
1361 cond = kArmCondGe;
1362 break;
1363 case OP_IF_GTZ:
1364 cond = kArmCondGt;
1365 break;
1366 case OP_IF_LEZ:
1367 cond = kArmCondLe;
1368 break;
1369 default:
1370 cond = (ArmConditionCode)0;
1371 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1372 }
1373 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1374 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1375 break;
1376 }
1377
1378 case OP_AGET_WIDE:
1379 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1380 break;
1381 case OP_AGET:
1382 case OP_AGET_OBJECT:
1383 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1384 break;
1385 case OP_AGET_BOOLEAN:
1386 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1387 rlDest, 0);
1388 break;
1389 case OP_AGET_BYTE:
1390 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1391 break;
1392 case OP_AGET_CHAR:
1393 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1394 rlDest, 1);
1395 break;
1396 case OP_AGET_SHORT:
1397 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1398 break;
1399 case OP_APUT_WIDE:
1400 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1401 break;
1402 case OP_APUT:
1403 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1404 break;
1405 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001406 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001407 break;
1408 case OP_APUT_SHORT:
1409 case OP_APUT_CHAR:
1410 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1411 rlSrc[0], 1);
1412 break;
1413 case OP_APUT_BYTE:
1414 case OP_APUT_BOOLEAN:
1415 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1416 rlSrc[0], 0);
1417 break;
1418
1419 case OP_IGET_WIDE:
1420 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001421 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001422 break;
1423
1424 case OP_IGET:
1425 case OP_IGET_VOLATILE:
1426 case OP_IGET_OBJECT:
1427 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001428 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001429 break;
1430
1431 case OP_IGET_BOOLEAN:
1432 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001433 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001434 break;
1435
1436 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001437 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001438 break;
1439
1440 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001441 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001442 break;
1443
1444 case OP_IPUT_WIDE:
1445 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001446 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001447 break;
1448
1449 case OP_IPUT_OBJECT:
1450 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001451 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001452 break;
1453
1454 case OP_IPUT:
1455 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001456 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001457 break;
1458
1459 case OP_IPUT_BOOLEAN:
1460 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001461 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001462 break;
1463
1464 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001465 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001466 break;
1467
1468 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001469 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001470 break;
1471
1472 case OP_SGET:
1473 case OP_SGET_OBJECT:
1474 case OP_SGET_BOOLEAN:
1475 case OP_SGET_BYTE:
1476 case OP_SGET_CHAR:
1477 case OP_SGET_SHORT:
1478 genSget(cUnit, mir, rlResult, rlDest);
1479 break;
1480
1481 case OP_SGET_WIDE:
1482 genSgetWide(cUnit, mir, rlResult, rlDest);
1483 break;
1484
1485 case OP_SPUT:
1486 case OP_SPUT_OBJECT:
1487 case OP_SPUT_BOOLEAN:
1488 case OP_SPUT_BYTE:
1489 case OP_SPUT_CHAR:
1490 case OP_SPUT_SHORT:
1491 genSput(cUnit, mir, rlSrc[0]);
1492 break;
1493
1494 case OP_SPUT_WIDE:
1495 genSputWide(cUnit, mir, rlSrc[0]);
1496 break;
1497
1498 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001499 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1500 true /*range*/);
1501 break;
buzbee67bf8852011-08-17 17:51:35 -07001502 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001503 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1504 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001505 break;
1506
1507 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001508 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1509 false /*range*/);
1510 break;
buzbee67bf8852011-08-17 17:51:35 -07001511 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001512 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1513 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001514 break;
1515
1516 case OP_INVOKE_VIRTUAL:
1517 case OP_INVOKE_VIRTUAL_RANGE:
1518 genInvokeVirtual(cUnit, mir);
1519 break;
1520
1521 case OP_INVOKE_SUPER:
1522 case OP_INVOKE_SUPER_RANGE:
1523 genInvokeSuper(cUnit, mir);
1524 break;
1525
1526 case OP_INVOKE_INTERFACE:
1527 case OP_INVOKE_INTERFACE_RANGE:
1528 genInvokeInterface(cUnit, mir);
1529 break;
1530
1531 case OP_NEG_INT:
1532 case OP_NOT_INT:
1533 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1534 break;
1535
1536 case OP_NEG_LONG:
1537 case OP_NOT_LONG:
1538 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1539 break;
1540
1541 case OP_NEG_FLOAT:
1542 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1543 break;
1544
1545 case OP_NEG_DOUBLE:
1546 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1547 break;
1548
1549 case OP_INT_TO_LONG:
1550 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1551 if (rlSrc[0].location == kLocPhysReg) {
1552 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1553 } else {
1554 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1555 }
1556 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1557 rlResult.lowReg, 31);
1558 storeValueWide(cUnit, rlDest, rlResult);
1559 break;
1560
1561 case OP_LONG_TO_INT:
1562 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1563 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1564 storeValue(cUnit, rlDest, rlSrc[0]);
1565 break;
1566
1567 case OP_INT_TO_BYTE:
1568 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1569 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1570 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1571 storeValue(cUnit, rlDest, rlResult);
1572 break;
1573
1574 case OP_INT_TO_SHORT:
1575 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1576 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1577 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1578 storeValue(cUnit, rlDest, rlResult);
1579 break;
1580
1581 case OP_INT_TO_CHAR:
1582 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1583 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1584 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1585 storeValue(cUnit, rlDest, rlResult);
1586 break;
1587
1588 case OP_INT_TO_FLOAT:
1589 case OP_INT_TO_DOUBLE:
1590 case OP_LONG_TO_FLOAT:
1591 case OP_LONG_TO_DOUBLE:
1592 case OP_FLOAT_TO_INT:
1593 case OP_FLOAT_TO_LONG:
1594 case OP_FLOAT_TO_DOUBLE:
1595 case OP_DOUBLE_TO_INT:
1596 case OP_DOUBLE_TO_LONG:
1597 case OP_DOUBLE_TO_FLOAT:
1598 genConversion(cUnit, mir);
1599 break;
1600
1601 case OP_ADD_INT:
1602 case OP_SUB_INT:
1603 case OP_MUL_INT:
1604 case OP_DIV_INT:
1605 case OP_REM_INT:
1606 case OP_AND_INT:
1607 case OP_OR_INT:
1608 case OP_XOR_INT:
1609 case OP_SHL_INT:
1610 case OP_SHR_INT:
1611 case OP_USHR_INT:
1612 case OP_ADD_INT_2ADDR:
1613 case OP_SUB_INT_2ADDR:
1614 case OP_MUL_INT_2ADDR:
1615 case OP_DIV_INT_2ADDR:
1616 case OP_REM_INT_2ADDR:
1617 case OP_AND_INT_2ADDR:
1618 case OP_OR_INT_2ADDR:
1619 case OP_XOR_INT_2ADDR:
1620 case OP_SHL_INT_2ADDR:
1621 case OP_SHR_INT_2ADDR:
1622 case OP_USHR_INT_2ADDR:
1623 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1624 break;
1625
1626 case OP_ADD_LONG:
1627 case OP_SUB_LONG:
1628 case OP_MUL_LONG:
1629 case OP_DIV_LONG:
1630 case OP_REM_LONG:
1631 case OP_AND_LONG:
1632 case OP_OR_LONG:
1633 case OP_XOR_LONG:
1634 case OP_ADD_LONG_2ADDR:
1635 case OP_SUB_LONG_2ADDR:
1636 case OP_MUL_LONG_2ADDR:
1637 case OP_DIV_LONG_2ADDR:
1638 case OP_REM_LONG_2ADDR:
1639 case OP_AND_LONG_2ADDR:
1640 case OP_OR_LONG_2ADDR:
1641 case OP_XOR_LONG_2ADDR:
1642 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1643 break;
1644
buzbee67bf8852011-08-17 17:51:35 -07001645 case OP_SHL_LONG:
1646 case OP_SHR_LONG:
1647 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001648 case OP_SHL_LONG_2ADDR:
1649 case OP_SHR_LONG_2ADDR:
1650 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001651 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1652 break;
1653
1654 case OP_ADD_FLOAT:
1655 case OP_SUB_FLOAT:
1656 case OP_MUL_FLOAT:
1657 case OP_DIV_FLOAT:
1658 case OP_REM_FLOAT:
1659 case OP_ADD_FLOAT_2ADDR:
1660 case OP_SUB_FLOAT_2ADDR:
1661 case OP_MUL_FLOAT_2ADDR:
1662 case OP_DIV_FLOAT_2ADDR:
1663 case OP_REM_FLOAT_2ADDR:
1664 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1665 break;
1666
1667 case OP_ADD_DOUBLE:
1668 case OP_SUB_DOUBLE:
1669 case OP_MUL_DOUBLE:
1670 case OP_DIV_DOUBLE:
1671 case OP_REM_DOUBLE:
1672 case OP_ADD_DOUBLE_2ADDR:
1673 case OP_SUB_DOUBLE_2ADDR:
1674 case OP_MUL_DOUBLE_2ADDR:
1675 case OP_DIV_DOUBLE_2ADDR:
1676 case OP_REM_DOUBLE_2ADDR:
1677 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1678 break;
1679
1680 case OP_RSUB_INT:
1681 case OP_ADD_INT_LIT16:
1682 case OP_MUL_INT_LIT16:
1683 case OP_DIV_INT_LIT16:
1684 case OP_REM_INT_LIT16:
1685 case OP_AND_INT_LIT16:
1686 case OP_OR_INT_LIT16:
1687 case OP_XOR_INT_LIT16:
1688 case OP_ADD_INT_LIT8:
1689 case OP_RSUB_INT_LIT8:
1690 case OP_MUL_INT_LIT8:
1691 case OP_DIV_INT_LIT8:
1692 case OP_REM_INT_LIT8:
1693 case OP_AND_INT_LIT8:
1694 case OP_OR_INT_LIT8:
1695 case OP_XOR_INT_LIT8:
1696 case OP_SHL_INT_LIT8:
1697 case OP_SHR_INT_LIT8:
1698 case OP_USHR_INT_LIT8:
1699 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1700 break;
1701
1702 default:
1703 res = true;
1704 }
1705 return res;
1706}
1707
1708static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1709 "kMirOpPhi",
1710 "kMirOpNullNRangeUpCheck",
1711 "kMirOpNullNRangeDownCheck",
1712 "kMirOpLowerBound",
1713 "kMirOpPunt",
1714 "kMirOpCheckInlinePrediction",
1715};
1716
1717/* Extended MIR instructions like PHI */
1718static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1719{
1720 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1721 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1722 strcpy(msg, extendedMIROpNames[opOffset]);
1723 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1724
1725 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1726 case kMirOpPhi: {
1727 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1728 op->flags.isNop = true;
1729 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1730 break;
1731 }
1732 default:
1733 break;
1734 }
1735}
1736
1737/* If there are any ins passed in registers that have not been promoted
1738 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001739 * Note: at this pointCopy any ins that are passed in register to their
1740 * home location */
buzbee67bf8852011-08-17 17:51:35 -07001741static void flushIns(CompilationUnit* cUnit)
1742{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001743 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001744 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001745 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1746 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001747 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001748 int startLoc = cUnit->method->NumRegisters() -
1749 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001750 for (int i = 0; i < inRegs; i++) {
1751 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001752 //TUNING: be smarter about flushing ins to frame
1753 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001754 if (loc.location == kLocPhysReg) {
1755 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001756 }
1757 }
1758
1759 // Handle special case of wide argument half in regs, half in frame
1760 if (inRegs == 3) {
1761 RegLocation loc = cUnit->regLocation[startLoc + 2];
1762 if (loc.wide && loc.location == kLocPhysReg) {
1763 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001764 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001765 inRegs++;
1766 }
1767 }
1768
1769 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001770 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001771 RegLocation loc = cUnit->regLocation[startLoc + i];
1772 if (loc.fpLocation == kLocPhysReg) {
1773 loc.location = kLocPhysReg;
1774 loc.fp = true;
1775 loc.lowReg = loc.fpLowReg;
1776 loc.highReg = loc.fpHighReg;
1777 }
1778 if (loc.location == kLocPhysReg) {
1779 if (loc.wide) {
1780 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1781 loc.lowReg, loc.highReg, INVALID_SREG);
1782 i++;
1783 } else {
buzbee561227c2011-09-02 15:28:19 -07001784 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001785 }
1786 }
1787 i++;
1788 }
1789}
1790
1791/* Handle the content in each basic block */
1792static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1793{
1794 MIR* mir;
1795 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1796 int blockId = bb->id;
1797
1798 cUnit->curBlock = bb;
1799 labelList[blockId].operands[0] = bb->startOffset;
1800
1801 /* Insert the block label */
1802 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1803 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1804
1805 oatClobberAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001806
1807 ArmLIR* headLIR = NULL;
1808
1809 if (bb->blockType == kEntryBlock) {
1810 /*
1811 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1812 * mechanism know so it doesn't try to use any of them when
1813 * expanding the frame or flushing. This leaves the utility
1814 * code with a single temp: r12. This should be enough.
1815 */
1816 oatLockTemp(cUnit, r0);
1817 oatLockTemp(cUnit, r1);
1818 oatLockTemp(cUnit, r2);
1819 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001820
1821 /*
1822 * We can safely skip the stack overflow check if we're
1823 * a leaf *and* our frame size < fudge factor.
1824 */
1825 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1826 ((size_t)cUnit->frameSize <
1827 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001828 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001829 if (!skipOverflowCheck) {
1830 /* Load stack limit */
1831 loadWordDisp(cUnit, rSELF,
1832 art::Thread::StackEndOffset().Int32Value(), r12);
1833 }
buzbee67bf8852011-08-17 17:51:35 -07001834 /* Spill core callee saves */
1835 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1836 /* Need to spill any FP regs? */
1837 if (cUnit->numFPSpills) {
1838 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1839 }
buzbeecefd1872011-09-09 09:59:52 -07001840 if (!skipOverflowCheck) {
1841 opRegRegImm(cUnit, kOpSub, rLR, rSP,
1842 cUnit->frameSize - (cUnit->numSpills * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001843 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1844 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001845 genRegCopy(cUnit, rSP, rLR); // Establish stack
1846 } else {
1847 opRegImm(cUnit, kOpSub, rSP,
1848 cUnit->frameSize - (cUnit->numSpills * 4));
1849 }
buzbee67bf8852011-08-17 17:51:35 -07001850 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1851 flushIns(cUnit);
1852 oatFreeTemp(cUnit, r0);
1853 oatFreeTemp(cUnit, r1);
1854 oatFreeTemp(cUnit, r2);
1855 oatFreeTemp(cUnit, r3);
1856 } else if (bb->blockType == kExitBlock) {
1857 newLIR0(cUnit, kArmPseudoMethodExit);
1858 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1859 /* Need to restore any FP callee saves? */
1860 if (cUnit->numFPSpills) {
1861 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1862 }
1863 if (cUnit->coreSpillMask & (1 << rLR)) {
1864 /* Unspill rLR to rPC */
1865 cUnit->coreSpillMask &= ~(1 << rLR);
1866 cUnit->coreSpillMask |= (1 << rPC);
1867 }
1868 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1869 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1870 /* We didn't pop to rPC, so must do a bv rLR */
1871 newLIR1(cUnit, kThumbBx, rLR);
1872 }
1873 }
1874
1875 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1876
1877 oatResetRegPool(cUnit);
buzbeef0cde542011-09-13 14:55:02 -07001878 oatClobberAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001879
1880 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1881 oatResetDefTracking(cUnit);
1882 }
1883
1884 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1885 handleExtendedMethodMIR(cUnit, mir);
1886 continue;
1887 }
1888
1889 cUnit->currentDalvikOffset = mir->offset;
1890
1891 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1892 InstructionFormat dalvikFormat =
1893 dexGetFormatFromOpcode(dalvikOpcode);
1894
1895 ArmLIR* boundaryLIR;
1896
1897 /* Mark the beginning of a Dalvik instruction for line tracking */
1898 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1899 (int) oatGetDalvikDisassembly(
1900 &mir->dalvikInsn, ""));
1901 /* Remember the first LIR for this block */
1902 if (headLIR == NULL) {
1903 headLIR = boundaryLIR;
1904 /* Set the first boundaryLIR as a scheduling barrier */
1905 headLIR->defMask = ENCODE_ALL;
1906 }
1907
1908 /* Don't generate the SSA annotation unless verbose mode is on */
1909 if (cUnit->printMe && mir->ssaRep) {
1910 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1911 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1912 }
1913
1914 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1915
1916 if (notHandled) {
1917 char buf[100];
1918 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1919 mir->offset,
1920 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1921 dalvikFormat);
1922 LOG(FATAL) << buf;
1923 }
1924 }
1925
1926 if (headLIR) {
1927 /*
1928 * Eliminate redundant loads/stores and delay stores into later
1929 * slots
1930 */
1931 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1932 cUnit->lastLIRInsn);
1933
1934 /*
1935 * Generate an unconditional branch to the fallthrough block.
1936 */
1937 if (bb->fallThrough) {
1938 genUnconditionalBranch(cUnit,
1939 &labelList[bb->fallThrough->id]);
1940 }
1941 }
1942 return false;
1943}
1944
1945/*
1946 * Nop any unconditional branches that go to the next instruction.
1947 * Note: new redundant branches may be inserted later, and we'll
1948 * use a check in final instruction assembly to nop those out.
1949 */
1950void removeRedundantBranches(CompilationUnit* cUnit)
1951{
1952 ArmLIR* thisLIR;
1953
1954 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1955 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1956 thisLIR = NEXT_LIR(thisLIR)) {
1957
1958 /* Branch to the next instruction */
1959 if ((thisLIR->opcode == kThumbBUncond) ||
1960 (thisLIR->opcode == kThumb2BUncond)) {
1961 ArmLIR* nextLIR = thisLIR;
1962
1963 while (true) {
1964 nextLIR = NEXT_LIR(nextLIR);
1965
1966 /*
1967 * Is the branch target the next instruction?
1968 */
1969 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1970 thisLIR->flags.isNop = true;
1971 break;
1972 }
1973
1974 /*
1975 * Found real useful stuff between the branch and the target.
1976 * Need to explicitly check the lastLIRInsn here because it
1977 * might be the last real instruction.
1978 */
1979 if (!isPseudoOpcode(nextLIR->opcode) ||
1980 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1981 break;
1982 }
1983 }
1984 }
1985}
1986
buzbee5ade1d22011-09-09 14:44:52 -07001987static void handleThrowLaunchpads(CompilationUnit *cUnit)
1988{
1989 ArmLIR** throwLabel =
1990 (ArmLIR **) cUnit->throwLaunchpads.elemList;
1991 int numElems = cUnit->throwLaunchpads.numUsed;
1992 int i;
1993
1994 for (i = 0; i < numElems; i++) {
1995 ArmLIR* lab = throwLabel[i];
1996 cUnit->currentDalvikOffset = lab->operands[1];
1997 oatAppendLIR(cUnit, (LIR *)lab);
1998 int funcOffset = 0;
1999 int v1 = lab->operands[2];
2000 int v2 = lab->operands[3];
2001 switch(lab->operands[0]) {
2002 case kArmThrowNullPointer:
2003 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2004 break;
2005 case kArmThrowArrayBounds:
2006 if (v2 != r0) {
2007 genRegCopy(cUnit, r0, v1);
2008 genRegCopy(cUnit, r1, v2);
2009 } else {
2010 if (v1 == r1) {
2011 genRegCopy(cUnit, r12, v1);
2012 genRegCopy(cUnit, r1, v2);
2013 genRegCopy(cUnit, r0, r12);
2014 } else {
2015 genRegCopy(cUnit, r1, v2);
2016 genRegCopy(cUnit, r0, v1);
2017 }
2018 }
2019 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2020 break;
2021 case kArmThrowDivZero:
2022 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2023 break;
2024 case kArmThrowVerificationError:
2025 loadConstant(cUnit, r0, v1);
2026 loadConstant(cUnit, r1, v2);
2027 funcOffset =
2028 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2029 break;
2030 case kArmThrowNegArraySize:
2031 genRegCopy(cUnit, r0, v1);
2032 funcOffset =
2033 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2034 break;
2035 case kArmThrowInternalError:
2036 genRegCopy(cUnit, r0, v1);
2037 funcOffset =
2038 OFFSETOF_MEMBER(Thread, pThrowInternalErrorFromCode);
2039 break;
2040 case kArmThrowRuntimeException:
2041 genRegCopy(cUnit, r0, v1);
2042 funcOffset =
2043 OFFSETOF_MEMBER(Thread, pThrowRuntimeExceptionFromCode);
2044 break;
2045 case kArmThrowNoSuchMethod:
2046 genRegCopy(cUnit, r0, v1);
2047 funcOffset =
2048 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2049 break;
buzbeeec5adf32011-09-11 15:25:43 -07002050 case kArmThrowStackOverflow:
2051 funcOffset =
2052 OFFSETOF_MEMBER(Thread, pStackOverflowFromCode);
2053 // Restore stack alignment
2054 opRegImm(cUnit, kOpAdd, rSP, cUnit->numSpills * 4);
2055 break;
buzbee5ade1d22011-09-09 14:44:52 -07002056 default:
2057 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2058 }
2059 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
buzbeeec5adf32011-09-11 15:25:43 -07002060 callUnwindableHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002061 }
2062}
2063
buzbee67bf8852011-08-17 17:51:35 -07002064void oatMethodMIR2LIR(CompilationUnit* cUnit)
2065{
2066 /* Used to hold the labels of each block */
2067 cUnit->blockLabelList =
2068 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2069
2070 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2071 kPreOrderDFSTraversal, false /* Iterative */);
2072 removeRedundantBranches(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002073
2074 handleThrowLaunchpads(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002075}
2076
2077/* Common initialization routine for an architecture family */
2078bool oatArchInit()
2079{
2080 int i;
2081
2082 for (i = 0; i < kArmLast; i++) {
2083 if (EncodingMap[i].opcode != i) {
2084 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2085 " is wrong: expecting " << i << ", seeing " <<
2086 (int)EncodingMap[i].opcode;
2087 }
2088 }
2089
2090 return oatArchVariantInit();
2091}
2092
2093/* Needed by the Assembler */
2094void oatSetupResourceMasks(ArmLIR* lir)
2095{
2096 setupResourceMasks(lir);
2097}
2098
2099/* Needed by the ld/st optmizatons */
2100ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2101{
2102 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2103}
2104
2105/* Needed by the register allocator */
2106ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2107{
2108 return genRegCopy(cUnit, rDest, rSrc);
2109}
2110
2111/* Needed by the register allocator */
2112void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2113 int srcLo, int srcHi)
2114{
2115 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2116}
2117
2118void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2119 int displacement, int rSrc, OpSize size)
2120{
2121 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2122}
2123
2124void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2125 int displacement, int rSrcLo, int rSrcHi)
2126{
2127 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2128}