blob: 9f89ff980754f70407745839faa26061734a6d42 [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;
55 int elems;
buzbeedfd3d702011-08-28 12:56:51 -070056 int typeId;
buzbee67bf8852011-08-17 17:51:35 -070057 if (isRange) {
58 elems = dInsn->vA;
buzbeedfd3d702011-08-28 12:56:51 -070059 typeId = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -070060 } else {
61 elems = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070062 typeId = dInsn->vC;
buzbee67bf8852011-08-17 17:51:35 -070063 }
buzbeedfd3d702011-08-28 12:56:51 -070064 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070065 loadWordDisp(cUnit, rSELF,
buzbee1da522d2011-09-04 11:22:20 -070066 OFFSETOF_MEMBER(Thread, pCheckAndAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070067 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
68 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
69 loadConstant(cUnit, r2, elems); // arg2 <- count
buzbeeec5adf32011-09-11 15:25:43 -070070 callUnwindableHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070071 /*
buzbeedfd3d702011-08-28 12:56:51 -070072 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
73 * return region. Because AllocFromCode placed the new array
74 * in r0, we'll just lock it into place. When debugger support is
75 * added, it may be necessary to additionally copy all return
76 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070077 */
buzbee67bf8852011-08-17 17:51:35 -070078 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070079
buzbee67bf8852011-08-17 17:51:35 -070080 // Having a range of 0 is legal
81 if (isRange && (dInsn->vA > 0)) {
82 /*
83 * Bit of ugliness here. We're going generate a mem copy loop
84 * on the register range, but it is possible that some regs
85 * in the range have been promoted. This is unlikely, but
86 * before generating the copy, we'll just force a flush
87 * of any regs in the source range that have been promoted to
88 * home location.
89 */
90 for (unsigned int i = 0; i < dInsn->vA; i++) {
91 RegLocation loc = oatUpdateLoc(cUnit,
92 oatGetSrc(cUnit, mir, i));
93 if (loc.location == kLocPhysReg) {
94 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
95 }
96 }
97 /*
98 * TUNING note: generated code here could be much improved, but
99 * this is an uncommon operation and isn't especially performance
100 * critical.
101 */
102 int rSrc = oatAllocTemp(cUnit);
103 int rDst = oatAllocTemp(cUnit);
104 int rIdx = oatAllocTemp(cUnit);
105 int rVal = rLR; // Using a lot of temps, rLR is known free here
106 // Set up source pointer
107 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
108 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
109 // Set up the target pointer
110 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700111 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700112 // Set up the loop counter (known to be > 0)
113 loadConstant(cUnit, rIdx, dInsn->vA);
114 // Generate the copy loop. Going backwards for convenience
115 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
116 target->defMask = ENCODE_ALL;
117 // Copy next element
118 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
119 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
120 // Use setflags encoding here
121 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
122 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
123 branch->generic.target = (LIR*)target;
124 } else if (!isRange) {
125 // TUNING: interleave
126 for (unsigned int i = 0; i < dInsn->vA; i++) {
127 RegLocation rlArg = loadValue(cUnit,
128 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700129 storeBaseDisp(cUnit, r0,
130 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700131 i * 4, rlArg.lowReg, kWord);
132 // If the loadValue caused a temp to be allocated, free it
133 if (oatIsTemp(cUnit, rlArg.lowReg)) {
134 oatFreeTemp(cUnit, rlArg.lowReg);
135 }
136 }
137 }
138}
139
140static void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
141{
buzbeee1931742011-08-28 21:15:53 -0700142 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
143 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700144 int fieldIdx = mir->dalvikInsn.vB;
145 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
146 if (field == NULL) {
147 // Slow path
buzbee34cd9e52011-09-08 14:31:52 -0700148 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
149 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700150 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
151 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700152 oatFlushAllRegs(cUnit);
153 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
154 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
155 loadCurrMethodDirect(cUnit, r1);
156 loadValueDirect(cUnit, rlSrc, r2);
buzbeeec5adf32011-09-11 15:25:43 -0700157 callUnwindableHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700158 oatClobberCallRegs(cUnit);
159 } else {
buzbee1da522d2011-09-04 11:22:20 -0700160 // fast path
161 int fieldOffset = field->GetOffset().Int32Value();
162 art::ClassLinker* class_linker = art::Runtime::Current()->
163 GetClassLinker();
164 const art::DexFile& dex_file = class_linker->
Elliott Hughesb1539062011-09-11 16:14:31 -0700165 FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
buzbee1da522d2011-09-04 11:22:20 -0700166 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
167 int typeIdx = field_id.class_idx_;
168 // Using fixed register to sync with slow path
169 int rMethod = r1;
170 oatLockTemp(cUnit, rMethod);
171 loadCurrMethodDirect(cUnit, rMethod);
172 int rBase = r0;
173 oatLockTemp(cUnit, rBase);
174 loadWordDisp(cUnit, rMethod,
175 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
176 rBase);
177 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
178 sizeof(int32_t*)* typeIdx, rBase);
179 // TUNING: fast path should fall through
180 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
181 loadWordDisp(cUnit, rSELF,
182 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
183 loadConstant(cUnit, r0, typeIdx);
buzbeeec5adf32011-09-11 15:25:43 -0700184 callUnwindableHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700185 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
186 skipTarget->defMask = ENCODE_ALL;
187 branchOver->generic.target = (LIR*)skipTarget;
188 rlSrc = oatGetSrc(cUnit, mir, 0);
189 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
190 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700191#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700192 if (field->IsVolatile()) {
193 oatGenMemBarrier(cUnit, kSY);
194 }
buzbee67bf8852011-08-17 17:51:35 -0700195#endif
buzbee1da522d2011-09-04 11:22:20 -0700196 if (isObject) {
197 markGCCard(cUnit, rlSrc.lowReg, rBase);
198 }
199 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700200 }
buzbee67bf8852011-08-17 17:51:35 -0700201}
202
203static void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
204{
buzbee1da522d2011-09-04 11:22:20 -0700205 int fieldIdx = mir->dalvikInsn.vB;
206 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700207 if (SLOW_FIELD_PATH || field == NULL) {
208 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
209 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700210 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700211 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700212 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
213 loadCurrMethodDirect(cUnit, r1);
214 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
buzbeeec5adf32011-09-11 15:25:43 -0700215 callUnwindableHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700216 oatClobberCallRegs(cUnit);
217 } else {
buzbee1da522d2011-09-04 11:22:20 -0700218 // fast path
219 int fieldOffset = field->GetOffset().Int32Value();
220 art::ClassLinker* class_linker = art::Runtime::Current()->
221 GetClassLinker();
222 const art::DexFile& dex_file = class_linker->
Elliott Hughesb1539062011-09-11 16:14:31 -0700223 FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
buzbee1da522d2011-09-04 11:22:20 -0700224 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
225 int typeIdx = field_id.class_idx_;
226 // Using fixed register to sync with slow path
227 int rMethod = r1;
228 oatLockTemp(cUnit, rMethod);
229 loadCurrMethodDirect(cUnit, r1);
230 int rBase = r0;
231 oatLockTemp(cUnit, rBase);
232 loadWordDisp(cUnit, rMethod,
233 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
234 rBase);
235 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
236 sizeof(int32_t*)* typeIdx, rBase);
237 // TUNING: fast path should fall through
238 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
239 loadWordDisp(cUnit, rSELF,
240 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
241 loadConstant(cUnit, r0, typeIdx);
buzbeeec5adf32011-09-11 15:25:43 -0700242 callUnwindableHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700243 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
244 skipTarget->defMask = ENCODE_ALL;
245 branchOver->generic.target = (LIR*)skipTarget;
246 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
247 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
248 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
249 rlSrc.highReg);
250#if ANDROID_SMP != 0
251 if (field->IsVolatile()) {
252 oatGenMemBarrier(cUnit, kSY);
253 }
buzbeec143c552011-08-20 17:38:58 -0700254#endif
buzbee1da522d2011-09-04 11:22:20 -0700255 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700256 }
buzbee67bf8852011-08-17 17:51:35 -0700257}
258
259
buzbee67bf8852011-08-17 17:51:35 -0700260static void genSgetWide(CompilationUnit* cUnit, MIR* mir,
261 RegLocation rlResult, RegLocation rlDest)
262{
buzbee1da522d2011-09-04 11:22:20 -0700263 int fieldIdx = mir->dalvikInsn.vB;
264 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700265 if (SLOW_FIELD_PATH || field == NULL) {
266 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
267 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700268 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700269 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700270 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
271 loadCurrMethodDirect(cUnit, r1);
buzbeeec5adf32011-09-11 15:25:43 -0700272 callUnwindableHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700273 RegLocation rlResult = oatGetReturnWide(cUnit);
274 storeValueWide(cUnit, rlDest, rlResult);
275 } else {
buzbee1da522d2011-09-04 11:22:20 -0700276 // Fast path
277 int fieldOffset = field->GetOffset().Int32Value();
278 art::ClassLinker* class_linker = art::Runtime::Current()->
279 GetClassLinker();
280 const art::DexFile& dex_file = class_linker->
Elliott Hughesb1539062011-09-11 16:14:31 -0700281 FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
buzbee1da522d2011-09-04 11:22:20 -0700282 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
283 int typeIdx = field_id.class_idx_;
284 // Using fixed register to sync with slow path
285 int rMethod = r1;
286 oatLockTemp(cUnit, rMethod);
287 loadCurrMethodDirect(cUnit, rMethod);
288 int rBase = r0;
289 oatLockTemp(cUnit, rBase);
290 loadWordDisp(cUnit, rMethod,
291 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
292 rBase);
293 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
294 sizeof(int32_t*)* typeIdx, rBase);
295 // TUNING: fast path should fall through
296 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
297 loadWordDisp(cUnit, rSELF,
298 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
299 loadConstant(cUnit, r0, typeIdx);
buzbeeec5adf32011-09-11 15:25:43 -0700300 callUnwindableHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700301 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
302 skipTarget->defMask = ENCODE_ALL;
303 branchOver->generic.target = (LIR*)skipTarget;
304 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
305 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
306#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700307 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700308 oatGenMemBarrier(cUnit, kSY);
309 }
buzbeec143c552011-08-20 17:38:58 -0700310#endif
buzbee1da522d2011-09-04 11:22:20 -0700311 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
312 rlResult.highReg, INVALID_SREG);
313 oatFreeTemp(cUnit, rBase);
314 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700315 }
buzbee67bf8852011-08-17 17:51:35 -0700316}
317
318static void genSget(CompilationUnit* cUnit, MIR* mir,
319 RegLocation rlResult, RegLocation rlDest)
320{
buzbee1da522d2011-09-04 11:22:20 -0700321 int fieldIdx = mir->dalvikInsn.vB;
322 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee1931742011-08-28 21:15:53 -0700323 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
324 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee34cd9e52011-09-08 14:31:52 -0700325 if (SLOW_FIELD_PATH || field == NULL) {
326 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
327 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700328 // Slow path
329 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
330 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700331 oatFlushAllRegs(cUnit);
332 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
333 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
334 loadCurrMethodDirect(cUnit, r1);
buzbeeec5adf32011-09-11 15:25:43 -0700335 callUnwindableHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700336 RegLocation rlResult = oatGetReturn(cUnit);
337 storeValue(cUnit, rlDest, rlResult);
338 } else {
buzbee1da522d2011-09-04 11:22:20 -0700339 // Fast path
340 int fieldOffset = field->GetOffset().Int32Value();
341 art::ClassLinker* class_linker = art::Runtime::Current()->
342 GetClassLinker();
343 const art::DexFile& dex_file = class_linker->
Elliott Hughesb1539062011-09-11 16:14:31 -0700344 FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
buzbee1da522d2011-09-04 11:22:20 -0700345 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
346 int typeIdx = field_id.class_idx_;
347 // Using fixed register to sync with slow path
348 int rMethod = r1;
349 oatLockTemp(cUnit, rMethod);
350 loadCurrMethodDirect(cUnit, rMethod);
351 int rBase = r0;
352 oatLockTemp(cUnit, rBase);
353 loadWordDisp(cUnit, rMethod,
354 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
355 rBase);
356 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
357 sizeof(int32_t*)* typeIdx, rBase);
358 // TUNING: fast path should fall through
359 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
360 loadWordDisp(cUnit, rSELF,
361 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
362 loadConstant(cUnit, r0, typeIdx);
buzbeeec5adf32011-09-11 15:25:43 -0700363 callUnwindableHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700364 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
365 skipTarget->defMask = ENCODE_ALL;
366 branchOver->generic.target = (LIR*)skipTarget;
367 rlDest = oatGetDest(cUnit, mir, 0);
368 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700369#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700370 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700371 oatGenMemBarrier(cUnit, kSY);
372 }
buzbee67bf8852011-08-17 17:51:35 -0700373#endif
buzbee1da522d2011-09-04 11:22:20 -0700374 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
375 oatFreeTemp(cUnit, rBase);
376 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700377 }
buzbee67bf8852011-08-17 17:51:35 -0700378}
379
buzbee561227c2011-09-02 15:28:19 -0700380typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
381 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700382
383/*
384 * Bit of a hack here - in leiu of a real scheduling pass,
385 * emit the next instruction in static & direct invoke sequences.
386 */
387static int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700388 DecodedInstruction* dInsn, int state,
389 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700390{
buzbee561227c2011-09-02 15:28:19 -0700391 DCHECK(rollback == NULL);
392 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700393 switch(state) {
394 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700395 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700396 break;
buzbee561227c2011-09-02 15:28:19 -0700397 case 1: // Get method->code_and_direct_methods_
398 loadWordDisp(cUnit, r0,
399 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
400 r0);
buzbee67bf8852011-08-17 17:51:35 -0700401 break;
buzbee561227c2011-09-02 15:28:19 -0700402 case 2: // Grab target method* and target code_
403 loadWordDisp(cUnit, r0,
404 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
405 loadWordDisp(cUnit, r0,
406 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700407 break;
408 default:
409 return -1;
410 }
411 return state + 1;
412}
413
buzbee67bf8852011-08-17 17:51:35 -0700414/*
415 * Bit of a hack here - in leiu of a real scheduling pass,
416 * emit the next instruction in a virtual invoke sequence.
417 * We can use rLR as a temp prior to target address loading
418 * Note also that we'll load the first argument ("this") into
419 * r1 here rather than the standard loadArgRegs.
420 */
421static int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700422 DecodedInstruction* dInsn, int state,
423 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700424{
buzbee561227c2011-09-02 15:28:19 -0700425 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700426 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700427 /*
428 * This is the fast path in which the target virtual method is
429 * fully resolved at compile time.
430 */
431 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
432 Get(dInsn->vB);
433 CHECK(baseMethod != NULL);
434 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700435 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700436 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700437 rlArg = oatGetSrc(cUnit, mir, 0);
438 loadValueDirectFixed(cUnit, rlArg, r1);
439 break;
buzbee561227c2011-09-02 15:28:19 -0700440 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700441 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700442 // get this->klass_ [use r1, set rLR]
443 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700444 break;
buzbee561227c2011-09-02 15:28:19 -0700445 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
446 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700447 break;
buzbee561227c2011-09-02 15:28:19 -0700448 case 3: // Get target method [use rLR, set r0]
449 loadWordDisp(cUnit, rLR, (target_idx * 4) +
450 art::Array::DataOffset().Int32Value(), r0);
451 break;
452 case 4: // Get the target compiled code address [uses r0, sets rLR]
453 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700454 break;
455 default:
456 return -1;
457 }
458 return state + 1;
459}
460
buzbee7b1b86d2011-08-26 18:59:10 -0700461static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700462 DecodedInstruction* dInsn, int state,
463 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700464{
buzbee561227c2011-09-02 15:28:19 -0700465 DCHECK(rollback != NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700466 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700467 ArmLIR* skipBranch;
468 ArmLIR* skipTarget;
469 /*
470 * This handles the case in which the base method is not fully
471 * resolved at compile time. We must generate code to test
472 * for resolution a run time, bail to the slow path if not to
473 * fill in all the tables. In the latter case, we'll restart at
474 * at the beginning of the sequence.
475 */
buzbee7b1b86d2011-08-26 18:59:10 -0700476 switch(state) {
477 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700478 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700479 break;
buzbee561227c2011-09-02 15:28:19 -0700480 case 1: // Get method->dex_cache_resolved_methods_
481 loadWordDisp(cUnit, r0,
482 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700483 break;
buzbee561227c2011-09-02 15:28:19 -0700484 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
485 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
486 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700487 break;
buzbee561227c2011-09-02 15:28:19 -0700488 case 3: // Resolved?
489 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
490 // Slowest path, bail to helper, rollback and retry
491 loadWordDisp(cUnit, rSELF,
492 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
493 loadConstant(cUnit, r1, dInsn->vB);
buzbeeec5adf32011-09-11 15:25:43 -0700494 callUnwindableHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700495 genUnconditionalBranch(cUnit, rollback);
496 // Resume normal slow path
497 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
498 skipTarget->defMask = ENCODE_ALL;
499 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700500 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700501 loadBaseDisp(cUnit, mir, rLR,
502 Method::GetMethodIndexOffset().Int32Value(), r0,
503 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700504 // Load "this" [set r1]
505 rlArg = oatGetSrc(cUnit, mir, 0);
506 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700507 break;
508 case 4:
509 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700510 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700511 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700512 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700513 break;
buzbee561227c2011-09-02 15:28:19 -0700514 case 5:
515 // get this->klass_->vtable_ [usr rLR, set rLR]
516 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
517 DCHECK((art::Array::DataOffset().Int32Value() & 0x3) == 0);
518 // In load shadow fold vtable_ object header size into method_index_
519 opRegImm(cUnit, kOpAdd, r0,
520 art::Array::DataOffset().Int32Value() / 4);
521 // Get target Method*
522 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
523 break;
524 case 6: // Get the target compiled code address [uses r0, sets rLR]
525 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700526 break;
527 default:
528 return -1;
529 }
530 return state + 1;
531}
532
buzbee67bf8852011-08-17 17:51:35 -0700533/* Load up to 3 arguments in r1..r3 */
534static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
535 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700536 int *args, NextCallInsn nextCallInsn, ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700537{
538 for (int i = 0; i < 3; i++) {
539 if (args[i] != INVALID_REG) {
buzbee1b4c8592011-08-31 10:43:51 -0700540 // Arguments are treated as a series of untyped 32-bit values.
buzbeee9a72f62011-09-04 17:59:07 -0700541 RegLocation rlArg = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700542 rlArg.wide = false;
buzbee67bf8852011-08-17 17:51:35 -0700543 loadValueDirectFixed(cUnit, rlArg, r1 + i);
buzbee561227c2011-09-02 15:28:19 -0700544 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700545 }
546 }
547 return callState;
548}
549
buzbee4a3164f2011-09-03 11:25:10 -0700550// Interleave launch code for INVOKE_INTERFACE.
buzbee67bf8852011-08-17 17:51:35 -0700551static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700552 DecodedInstruction* dInsn, int state,
553 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700554{
buzbee67bf8852011-08-17 17:51:35 -0700555 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700556 case 0: // Load trampoline target
557 loadWordDisp(cUnit, rSELF,
558 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
559 rLR);
560 // Load r0 with method index
561 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700562 break;
buzbee67bf8852011-08-17 17:51:35 -0700563 default:
564 return -1;
565 }
566 return state + 1;
567}
568
buzbee67bf8852011-08-17 17:51:35 -0700569/*
570 * Interleave launch code for INVOKE_SUPER. See comments
571 * for nextVCallIns.
572 */
573static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700574 DecodedInstruction* dInsn, int state,
575 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700576{
buzbee4a3164f2011-09-03 11:25:10 -0700577 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700578 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700579 /*
580 * This is the fast path in which the target virtual method is
581 * fully resolved at compile time. Note also that this path assumes
582 * that the check to verify that the target method index falls
583 * within the size of the super's vtable has been done at compile-time.
584 */
585 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
586 Get(dInsn->vB);
587 CHECK(baseMethod != NULL);
588 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
589 CHECK(superClass != NULL);
590 int32_t target_idx = baseMethod->GetMethodIndex();
591 CHECK(superClass->GetVTable()->GetLength() > target_idx);
592 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
593 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700594 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700595 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700596 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700597 // Load "this" [set r1]
598 rlArg = oatGetSrc(cUnit, mir, 0);
599 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700600 // Get method->declaring_class_ [use r0, set rLR]
601 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
602 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700603 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700604 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700605 break;
606 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
607 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
608 rLR);
609 break;
610 case 2: // Get ...->super_class_->vtable [u/s rLR]
611 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
612 break;
613 case 3: // Get target method [use rLR, set r0]
614 loadWordDisp(cUnit, rLR, (target_idx * 4) +
615 art::Array::DataOffset().Int32Value(), r0);
616 break;
617 case 4: // Get the target compiled code address [uses r0, sets rLR]
618 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
619 break;
buzbee67bf8852011-08-17 17:51:35 -0700620 default:
621 return -1;
622 }
buzbee4a3164f2011-09-03 11:25:10 -0700623 return state + 1;
624}
625
626/* Slow-path version of nextSuperCallInsn */
627static int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
628 DecodedInstruction* dInsn, int state,
629 ArmLIR* rollback)
630{
631 DCHECK(rollback != NULL);
632 RegLocation rlArg;
633 ArmLIR* skipBranch;
634 ArmLIR* skipTarget;
635 int tReg;
636 /*
637 * This handles the case in which the base method is not fully
638 * resolved at compile time. We must generate code to test
639 * for resolution a run time, bail to the slow path if not to
640 * fill in all the tables. In the latter case, we'll restart at
641 * at the beginning of the sequence.
642 */
643 switch(state) {
644 case 0: // Get the current Method* [sets r0]
645 loadCurrMethodDirect(cUnit, r0);
646 break;
647 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
648 loadWordDisp(cUnit, r0,
649 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
650 break;
651 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
652 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
653 art::Array::DataOffset().Int32Value(), rLR);
654 break;
655 case 3: // Resolved?
656 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
657 // Slowest path, bail to helper, rollback and retry
658 loadWordDisp(cUnit, rSELF,
659 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
660 loadConstant(cUnit, r1, dInsn->vB);
buzbeeec5adf32011-09-11 15:25:43 -0700661 callUnwindableHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700662 genUnconditionalBranch(cUnit, rollback);
663 // Resume normal slow path
664 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
665 skipTarget->defMask = ENCODE_ALL;
666 skipBranch->generic.target = (LIR*)skipTarget;
667 // Get base_method->method_index [usr rLR, set rLR]
668 loadBaseDisp(cUnit, mir, rLR,
669 Method::GetMethodIndexOffset().Int32Value(), rLR,
670 kUnsignedHalf, INVALID_SREG);
671 // Load "this" [set r1]
672 rlArg = oatGetSrc(cUnit, mir, 0);
673 loadValueDirectFixed(cUnit, rlArg, r1);
674 // Load curMethod->declaring_class_ [uses r0, sets r0]
675 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
676 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700677 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700678 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700679 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700680 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
681 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700682 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700683 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700684 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700685 // Range check, throw NSM on failure
686 tReg = oatAllocTemp(cUnit);
687 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
688 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700689 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
690 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700691 oatFreeTemp(cUnit, tReg);
692 }
buzbee6a0f7f52011-09-05 16:14:20 -0700693 // Adjust vtable_ base past object header
694 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700695 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700696 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700697 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700698 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700699 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
700 break;
701 default:
702 return -1;
703 }
buzbee67bf8852011-08-17 17:51:35 -0700704 return state + 1;
705}
706
707/*
708 * Load up to 5 arguments, the first three of which will be in
709 * r1 .. r3. On entry r0 contains the current method pointer,
710 * and as part of the load sequence, it must be replaced with
711 * the target method pointer. Note, this may also be called
712 * for "range" variants if the number of arguments is 5 or fewer.
713 */
714static int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
715 DecodedInstruction* dInsn, int callState,
716 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700717 NextCallInsn nextCallInsn, ArmLIR* rollback,
718 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700719{
720 RegLocation rlArg;
721 int registerArgs[3];
722
723 /* If no arguments, just return */
724 if (dInsn->vA == 0)
725 return callState;
726
buzbee561227c2011-09-02 15:28:19 -0700727 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700728
729 /*
730 * Load frame arguments arg4 & arg5 first. Coded a little odd to
731 * pre-schedule the method pointer target.
732 */
733 for (unsigned int i=3; i < dInsn->vA; i++) {
734 int reg;
buzbeeec5adf32011-09-11 15:25:43 -0700735 // Treating args as untyped 32-bit chunks
736 rlArg = oatGetRawSrc(cUnit, mir, i);
737 rlArg.wide = false;
738 rlArg = oatUpdateLoc(cUnit, rlArg);
buzbee67bf8852011-08-17 17:51:35 -0700739 if (rlArg.location == kLocPhysReg) {
740 reg = rlArg.lowReg;
741 } else {
buzbee109bd6a2011-09-06 13:58:41 -0700742 // r3 is the last arg register loaded, so can safely be used here
743 reg = r3;
744 loadValueDirectFixed(cUnit, rlArg, reg);
buzbee561227c2011-09-02 15:28:19 -0700745 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700746 }
747 storeBaseDisp(cUnit, rSP, (i + 1) * 4, reg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700748 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700749 }
750
751 /* Load register arguments r1..r3 */
buzbeee9a72f62011-09-04 17:59:07 -0700752 for (unsigned int i = 0; i < 3; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700753 if (i < dInsn->vA)
754 registerArgs[i] = (isRange) ? dInsn->vC + i : i;
755 else
756 registerArgs[i] = INVALID_REG;
757 }
buzbeee9a72f62011-09-04 17:59:07 -0700758 if (skipThis) {
759 registerArgs[0] = INVALID_REG;
760 }
buzbee67bf8852011-08-17 17:51:35 -0700761 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
buzbee561227c2011-09-02 15:28:19 -0700762 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700763
buzbee6a0f7f52011-09-05 16:14:20 -0700764 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700765 // Load direct & need a "this" null check?
766 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700767 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700768 }
769 return callState;
770}
771
772/*
773 * May have 0+ arguments (also used for jumbo). Note that
774 * source virtual registers may be in physical registers, so may
775 * need to be flushed to home location before copying. This
776 * applies to arg3 and above (see below).
777 *
778 * Two general strategies:
779 * If < 20 arguments
780 * Pass args 3-18 using vldm/vstm block copy
781 * Pass arg0, arg1 & arg2 in r1-r3
782 * If 20+ arguments
783 * Pass args arg19+ using memcpy block copy
784 * Pass arg0, arg1 & arg2 in r1-r3
785 *
786 */
787static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
788 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700789 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700790 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700791{
792 int firstArg = dInsn->vC;
793 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700794 int registerArgs[3];
795
buzbee67bf8852011-08-17 17:51:35 -0700796 // If we can treat it as non-range (Jumbo ops will use range form)
797 if (numArgs <= 5)
798 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700799 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700800 /*
801 * Make sure range list doesn't span the break between in normal
802 * Dalvik vRegs and the ins.
803 */
buzbee1b4c8592011-08-31 10:43:51 -0700804 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700805 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700806 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
807 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700808 }
809
810 /*
811 * First load the non-register arguments. Both forms expect all
812 * of the source arguments to be in their home frame location, so
813 * scan the sReg names and flush any that have been promoted to
814 * frame backing storage.
815 */
816 // Scan the rest of the args - if in physReg flush to memory
buzbee0c7f26d2011-09-07 12:28:51 -0700817 for (int i = 3; i < numArgs; i++) {
buzbeee9a72f62011-09-04 17:59:07 -0700818 RegLocation loc = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700819 if (loc.wide) {
820 loc = oatUpdateLocWide(cUnit, loc);
821 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
822 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
823 loc.highReg);
buzbee561227c2011-09-02 15:28:19 -0700824 callState = nextCallInsn(cUnit, mir, dInsn, callState,
825 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700826 }
827 } else {
828 loc = oatUpdateLoc(cUnit, loc);
829 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
830 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700831 callState = nextCallInsn(cUnit, mir, dInsn, callState,
832 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700833 }
buzbee67bf8852011-08-17 17:51:35 -0700834 }
835 }
836
837 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
838 int outsOffset = 4 /* Method* */ + (3 * 4);
839 if (numArgs >= 20) {
840 // Generate memcpy, but first make sure all of
841 opRegRegImm(cUnit, kOpAdd, r0, rSP, startOffset);
842 opRegRegImm(cUnit, kOpAdd, r1, rSP, outsOffset);
843 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
844 loadConstant(cUnit, r2, (numArgs - 3) * 4);
buzbeeec5adf32011-09-11 15:25:43 -0700845 callNoUnwindHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700846 } else {
847 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700848 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700849 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700850 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700851 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
852 //TUNING: loosen barrier
853 ld->defMask = ENCODE_ALL;
854 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700855 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700856 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700857 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700858 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
859 setMemRefType(st, false /* isLoad */, kDalvikReg);
860 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700861 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700862 }
863
864 // Handle the 1st 3 in r1, r2 & r3
buzbeee9a72f62011-09-04 17:59:07 -0700865 for (unsigned int i = 0; i < 3; i++) {
866 if (i < dInsn->vA)
867 registerArgs[i] = dInsn->vC + i;
868 else
869 registerArgs[i] = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700870 }
buzbeee9a72f62011-09-04 17:59:07 -0700871 if (skipThis) {
872 registerArgs[0] = INVALID_REG;
873 }
874 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
875 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700876
buzbee561227c2011-09-02 15:28:19 -0700877 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700878 return callState;
879}
880
buzbee2a475e72011-09-07 17:19:17 -0700881#ifdef DISPLAY_MISSING_TARGETS
882// Debugging routine - if null target, branch to DebugMe
883static void genShowTarget(CompilationUnit* cUnit)
884{
885 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
886 loadWordDisp(cUnit, rSELF,
887 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
888 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
889 target->defMask = -1;
890 branchOver->generic.target = (LIR*)target;
891}
892#endif
893
buzbee561227c2011-09-02 15:28:19 -0700894static void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
895 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700896{
897 DecodedInstruction* dInsn = &mir->dalvikInsn;
898 int callState = 0;
899 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700900 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700901 NextCallInsn nextCallInsn = nextSDCallInsn;
902
buzbee109bd6a2011-09-06 13:58:41 -0700903 // Explicit register usage
904 oatLockCallTemps(cUnit);
905
buzbee561227c2011-09-02 15:28:19 -0700906 if (range) {
907 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700908 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700909 } else {
910 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700911 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700912 }
buzbee67bf8852011-08-17 17:51:35 -0700913 // Finish up any of the call sequence not interleaved in arg loading
914 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700915 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700916 }
buzbee2a475e72011-09-07 17:19:17 -0700917#ifdef DISPLAY_MISSING_TARGETS
918 genShowTarget(cUnit);
919#endif
buzbeeec5adf32011-09-11 15:25:43 -0700920 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700921}
922
buzbee4a3164f2011-09-03 11:25:10 -0700923/*
924 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
925 * which will locate the target and continue on via a tail call.
926 */
buzbee67bf8852011-08-17 17:51:35 -0700927static void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
928{
929 DecodedInstruction* dInsn = &mir->dalvikInsn;
930 int callState = 0;
931 ArmLIR* nullCk;
buzbee109bd6a2011-09-06 13:58:41 -0700932
933 // Explicit register usage
934 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700935 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700936 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700937 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
938 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700939 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -0700940 false);
buzbee67bf8852011-08-17 17:51:35 -0700941 else
942 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -0700943 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -0700944 // Finish up any of the call sequence not interleaved in arg loading
945 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700946 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700947 }
buzbee2a475e72011-09-07 17:19:17 -0700948#ifdef DISPLAY_MISSING_TARGETS
949 genShowTarget(cUnit);
950#endif
buzbeeec5adf32011-09-11 15:25:43 -0700951 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700952}
953
954static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
955{
956 DecodedInstruction* dInsn = &mir->dalvikInsn;
957 int callState = 0;
958 ArmLIR* nullCk;
buzbee4a3164f2011-09-03 11:25:10 -0700959 ArmLIR* rollback;
960 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
961 Get(dInsn->vB);
962 NextCallInsn nextCallInsn;
963 bool fastPath = true;
buzbee109bd6a2011-09-06 13:58:41 -0700964
965 // Explicit register usage
966 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700967 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -0700968 fastPath = false;
969 } else {
970 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
971 if (superClass == NULL) {
972 fastPath = false;
973 } else {
974 int32_t target_idx = baseMethod->GetMethodIndex();
975 if (superClass->GetVTable()->GetLength() <= target_idx) {
976 fastPath = false;
977 } else {
978 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
979 }
980 }
981 }
982 if (fastPath) {
983 nextCallInsn = nextSuperCallInsn;
984 rollback = NULL;
985 } else {
986 nextCallInsn = nextSuperCallInsnSP;
987 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
988 rollback->defMask = -1;
989 }
buzbee67bf8852011-08-17 17:51:35 -0700990 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
991 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700992 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700993 else
994 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700995 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700996 // Finish up any of the call sequence not interleaved in arg loading
997 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -0700998 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700999 }
buzbee2a475e72011-09-07 17:19:17 -07001000#ifdef DISPLAY_MISSING_TARGETS
1001 genShowTarget(cUnit);
1002#endif
buzbeeec5adf32011-09-11 15:25:43 -07001003 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001004}
1005
1006static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
1007{
1008 DecodedInstruction* dInsn = &mir->dalvikInsn;
1009 int callState = 0;
1010 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -07001011 ArmLIR* rollback;
1012 Method* method = cUnit->method->GetDexCacheResolvedMethods()->
1013 Get(dInsn->vB);
1014 NextCallInsn nextCallInsn;
buzbee7b1b86d2011-08-26 18:59:10 -07001015
buzbee109bd6a2011-09-06 13:58:41 -07001016 // Explicit register usage
1017 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001018 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001019 // Slow path
1020 nextCallInsn = nextVCallInsnSP;
1021 // If we need a slow-path callout, we'll restart here
1022 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1023 rollback->defMask = -1;
1024 } else {
1025 // Fast path
1026 nextCallInsn = nextVCallInsn;
1027 rollback = NULL;
1028 }
buzbee67bf8852011-08-17 17:51:35 -07001029 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
1030 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001031 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001032 else
1033 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001034 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001035 // Finish up any of the call sequence not interleaved in arg loading
1036 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001037 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001038 }
buzbee2a475e72011-09-07 17:19:17 -07001039#ifdef DISPLAY_MISSING_TARGETS
1040 genShowTarget(cUnit);
1041#endif
buzbeeec5adf32011-09-11 15:25:43 -07001042 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001043}
1044
buzbee67bf8852011-08-17 17:51:35 -07001045static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
1046 BasicBlock* bb, ArmLIR* labelList)
1047{
1048 bool res = false; // Assume success
1049 RegLocation rlSrc[3];
1050 RegLocation rlDest = badLoc;
1051 RegLocation rlResult = badLoc;
1052 Opcode opcode = mir->dalvikInsn.opcode;
1053
1054 /* Prep Src and Dest locations */
1055 int nextSreg = 0;
1056 int nextLoc = 0;
1057 int attrs = oatDataFlowAttributes[opcode];
1058 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1059 if (attrs & DF_UA) {
1060 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1061 nextSreg++;
1062 } else if (attrs & DF_UA_WIDE) {
1063 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1064 nextSreg + 1);
1065 nextSreg+= 2;
1066 }
1067 if (attrs & DF_UB) {
1068 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1069 nextSreg++;
1070 } else if (attrs & DF_UB_WIDE) {
1071 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1072 nextSreg + 1);
1073 nextSreg+= 2;
1074 }
1075 if (attrs & DF_UC) {
1076 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1077 } else if (attrs & DF_UC_WIDE) {
1078 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1079 nextSreg + 1);
1080 }
1081 if (attrs & DF_DA) {
1082 rlDest = oatGetDest(cUnit, mir, 0);
1083 } else if (attrs & DF_DA_WIDE) {
1084 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1085 }
1086
1087 switch(opcode) {
1088 case OP_NOP:
1089 break;
1090
1091 case OP_MOVE_EXCEPTION:
1092 int exOffset;
1093 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001094 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001095 resetReg = oatAllocTemp(cUnit);
1096 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1097 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1098 loadConstant(cUnit, resetReg, 0);
1099 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1100 storeValue(cUnit, rlDest, rlResult);
1101 break;
1102
1103 case OP_RETURN_VOID:
1104 break;
1105
1106 case OP_RETURN:
1107 case OP_RETURN_OBJECT:
1108 storeValue(cUnit, retLoc, rlSrc[0]);
1109 break;
1110
1111 case OP_RETURN_WIDE:
1112 rlDest = retLocWide;
1113 rlDest.fp = rlSrc[0].fp;
1114 storeValueWide(cUnit, rlDest, rlSrc[0]);
1115 break;
1116
1117 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001118 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001119 break; // Nop - combined w/ previous invoke
1120 /*
1121 * Somewhat hacky here. Because we're now passing
1122 * return values in registers, we have to let the
1123 * register allocation utilities know that the return
1124 * registers are live and may not be used for address
1125 * formation in storeValueWide.
1126 */
1127 assert(retLocWide.lowReg == r0);
buzbee1da522d2011-09-04 11:22:20 -07001128 assert(retLocWide.highReg == r1);
buzbee67bf8852011-08-17 17:51:35 -07001129 oatLockTemp(cUnit, retLocWide.lowReg);
1130 oatLockTemp(cUnit, retLocWide.highReg);
1131 storeValueWide(cUnit, rlDest, retLocWide);
1132 oatFreeTemp(cUnit, retLocWide.lowReg);
1133 oatFreeTemp(cUnit, retLocWide.highReg);
1134 break;
1135
1136 case OP_MOVE_RESULT:
1137 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001138 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001139 break; // Nop - combined w/ previous invoke
1140 /* See comment for OP_MOVE_RESULT_WIDE */
1141 assert(retLoc.lowReg == r0);
1142 oatLockTemp(cUnit, retLoc.lowReg);
1143 storeValue(cUnit, rlDest, retLoc);
1144 oatFreeTemp(cUnit, retLoc.lowReg);
1145 break;
1146
1147 case OP_MOVE:
1148 case OP_MOVE_OBJECT:
1149 case OP_MOVE_16:
1150 case OP_MOVE_OBJECT_16:
1151 case OP_MOVE_FROM16:
1152 case OP_MOVE_OBJECT_FROM16:
1153 storeValue(cUnit, rlDest, rlSrc[0]);
1154 break;
1155
1156 case OP_MOVE_WIDE:
1157 case OP_MOVE_WIDE_16:
1158 case OP_MOVE_WIDE_FROM16:
1159 storeValueWide(cUnit, rlDest, rlSrc[0]);
1160 break;
1161
1162 case OP_CONST:
1163 case OP_CONST_4:
1164 case OP_CONST_16:
1165 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1166 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1167 storeValue(cUnit, rlDest, rlResult);
1168 break;
1169
1170 case OP_CONST_HIGH16:
1171 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1172 loadConstantNoClobber(cUnit, rlResult.lowReg,
1173 mir->dalvikInsn.vB << 16);
1174 storeValue(cUnit, rlDest, rlResult);
1175 break;
1176
1177 case OP_CONST_WIDE_16:
1178 case OP_CONST_WIDE_32:
1179 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1180 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1181 //TUNING: do high separately to avoid load dependency
1182 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1183 storeValueWide(cUnit, rlDest, rlResult);
1184 break;
1185
1186 case OP_CONST_WIDE:
1187 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1188 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001189 mir->dalvikInsn.vB_wide & 0xffffffff,
1190 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001191 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001192 break;
1193
1194 case OP_CONST_WIDE_HIGH16:
1195 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1196 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1197 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001198 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001199 break;
1200
1201 case OP_MONITOR_ENTER:
1202 genMonitorEnter(cUnit, mir, rlSrc[0]);
1203 break;
1204
1205 case OP_MONITOR_EXIT:
1206 genMonitorExit(cUnit, mir, rlSrc[0]);
1207 break;
1208
1209 case OP_CHECK_CAST:
1210 genCheckCast(cUnit, mir, rlSrc[0]);
1211 break;
1212
1213 case OP_INSTANCE_OF:
1214 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1215 break;
1216
1217 case OP_NEW_INSTANCE:
1218 genNewInstance(cUnit, mir, rlDest);
1219 break;
1220
1221 case OP_THROW:
1222 genThrow(cUnit, mir, rlSrc[0]);
1223 break;
1224
buzbee5ade1d22011-09-09 14:44:52 -07001225 case OP_THROW_VERIFICATION_ERROR:
1226 loadWordDisp(cUnit, rSELF,
1227 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1228 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1229 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
buzbeeec5adf32011-09-11 15:25:43 -07001230 callUnwindableHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001231 break;
1232
buzbee67bf8852011-08-17 17:51:35 -07001233 case OP_ARRAY_LENGTH:
1234 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001235 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001236 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001237 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001238 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1239 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1240 rlResult.lowReg);
1241 storeValue(cUnit, rlDest, rlResult);
1242 break;
1243
1244 case OP_CONST_STRING:
1245 case OP_CONST_STRING_JUMBO:
1246 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1247 break;
1248
1249 case OP_CONST_CLASS:
1250 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1251 break;
1252
1253 case OP_FILL_ARRAY_DATA:
1254 genFillArrayData(cUnit, mir, rlSrc[0]);
1255 break;
1256
1257 case OP_FILLED_NEW_ARRAY:
1258 genFilledNewArray(cUnit, mir, false /* not range */);
1259 break;
1260
1261 case OP_FILLED_NEW_ARRAY_RANGE:
1262 genFilledNewArray(cUnit, mir, true /* range */);
1263 break;
1264
1265 case OP_NEW_ARRAY:
1266 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1267 break;
1268
1269 case OP_GOTO:
1270 case OP_GOTO_16:
1271 case OP_GOTO_32:
1272 // TUNING: add MIR flag to disable when unnecessary
1273 bool backwardBranch;
1274 backwardBranch = (bb->taken->startOffset <= mir->offset);
1275 if (backwardBranch) {
1276 genSuspendPoll(cUnit, mir);
1277 }
1278 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1279 break;
1280
1281 case OP_PACKED_SWITCH:
1282 genPackedSwitch(cUnit, mir, rlSrc[0]);
1283 break;
1284
1285 case OP_SPARSE_SWITCH:
1286 genSparseSwitch(cUnit, mir, rlSrc[0]);
1287 break;
1288
1289 case OP_CMPL_FLOAT:
1290 case OP_CMPG_FLOAT:
1291 case OP_CMPL_DOUBLE:
1292 case OP_CMPG_DOUBLE:
1293 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1294 break;
1295
1296 case OP_CMP_LONG:
1297 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1298 break;
1299
1300 case OP_IF_EQ:
1301 case OP_IF_NE:
1302 case OP_IF_LT:
1303 case OP_IF_GE:
1304 case OP_IF_GT:
1305 case OP_IF_LE: {
1306 bool backwardBranch;
1307 ArmConditionCode cond;
1308 backwardBranch = (bb->taken->startOffset <= mir->offset);
1309 if (backwardBranch) {
1310 genSuspendPoll(cUnit, mir);
1311 }
1312 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1313 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1314 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1315 switch(opcode) {
1316 case OP_IF_EQ:
1317 cond = kArmCondEq;
1318 break;
1319 case OP_IF_NE:
1320 cond = kArmCondNe;
1321 break;
1322 case OP_IF_LT:
1323 cond = kArmCondLt;
1324 break;
1325 case OP_IF_GE:
1326 cond = kArmCondGe;
1327 break;
1328 case OP_IF_GT:
1329 cond = kArmCondGt;
1330 break;
1331 case OP_IF_LE:
1332 cond = kArmCondLe;
1333 break;
1334 default:
1335 cond = (ArmConditionCode)0;
1336 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1337 }
1338 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1339 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1340 break;
1341 }
1342
1343 case OP_IF_EQZ:
1344 case OP_IF_NEZ:
1345 case OP_IF_LTZ:
1346 case OP_IF_GEZ:
1347 case OP_IF_GTZ:
1348 case OP_IF_LEZ: {
1349 bool backwardBranch;
1350 ArmConditionCode cond;
1351 backwardBranch = (bb->taken->startOffset <= mir->offset);
1352 if (backwardBranch) {
1353 genSuspendPoll(cUnit, mir);
1354 }
1355 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1356 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1357 switch(opcode) {
1358 case OP_IF_EQZ:
1359 cond = kArmCondEq;
1360 break;
1361 case OP_IF_NEZ:
1362 cond = kArmCondNe;
1363 break;
1364 case OP_IF_LTZ:
1365 cond = kArmCondLt;
1366 break;
1367 case OP_IF_GEZ:
1368 cond = kArmCondGe;
1369 break;
1370 case OP_IF_GTZ:
1371 cond = kArmCondGt;
1372 break;
1373 case OP_IF_LEZ:
1374 cond = kArmCondLe;
1375 break;
1376 default:
1377 cond = (ArmConditionCode)0;
1378 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1379 }
1380 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1381 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1382 break;
1383 }
1384
1385 case OP_AGET_WIDE:
1386 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1387 break;
1388 case OP_AGET:
1389 case OP_AGET_OBJECT:
1390 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1391 break;
1392 case OP_AGET_BOOLEAN:
1393 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1394 rlDest, 0);
1395 break;
1396 case OP_AGET_BYTE:
1397 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1398 break;
1399 case OP_AGET_CHAR:
1400 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1401 rlDest, 1);
1402 break;
1403 case OP_AGET_SHORT:
1404 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1405 break;
1406 case OP_APUT_WIDE:
1407 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1408 break;
1409 case OP_APUT:
1410 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1411 break;
1412 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001413 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001414 break;
1415 case OP_APUT_SHORT:
1416 case OP_APUT_CHAR:
1417 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1418 rlSrc[0], 1);
1419 break;
1420 case OP_APUT_BYTE:
1421 case OP_APUT_BOOLEAN:
1422 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1423 rlSrc[0], 0);
1424 break;
1425
1426 case OP_IGET_WIDE:
1427 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001428 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001429 break;
1430
1431 case OP_IGET:
1432 case OP_IGET_VOLATILE:
1433 case OP_IGET_OBJECT:
1434 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001435 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001436 break;
1437
1438 case OP_IGET_BOOLEAN:
1439 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001440 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001441 break;
1442
1443 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001444 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001445 break;
1446
1447 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001448 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001449 break;
1450
1451 case OP_IPUT_WIDE:
1452 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001453 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001454 break;
1455
1456 case OP_IPUT_OBJECT:
1457 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001458 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001459 break;
1460
1461 case OP_IPUT:
1462 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001463 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001464 break;
1465
1466 case OP_IPUT_BOOLEAN:
1467 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001468 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001469 break;
1470
1471 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001472 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001473 break;
1474
1475 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001476 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001477 break;
1478
1479 case OP_SGET:
1480 case OP_SGET_OBJECT:
1481 case OP_SGET_BOOLEAN:
1482 case OP_SGET_BYTE:
1483 case OP_SGET_CHAR:
1484 case OP_SGET_SHORT:
1485 genSget(cUnit, mir, rlResult, rlDest);
1486 break;
1487
1488 case OP_SGET_WIDE:
1489 genSgetWide(cUnit, mir, rlResult, rlDest);
1490 break;
1491
1492 case OP_SPUT:
1493 case OP_SPUT_OBJECT:
1494 case OP_SPUT_BOOLEAN:
1495 case OP_SPUT_BYTE:
1496 case OP_SPUT_CHAR:
1497 case OP_SPUT_SHORT:
1498 genSput(cUnit, mir, rlSrc[0]);
1499 break;
1500
1501 case OP_SPUT_WIDE:
1502 genSputWide(cUnit, mir, rlSrc[0]);
1503 break;
1504
1505 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001506 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1507 true /*range*/);
1508 break;
buzbee67bf8852011-08-17 17:51:35 -07001509 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001510 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1511 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001512 break;
1513
1514 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001515 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1516 false /*range*/);
1517 break;
buzbee67bf8852011-08-17 17:51:35 -07001518 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001519 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1520 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001521 break;
1522
1523 case OP_INVOKE_VIRTUAL:
1524 case OP_INVOKE_VIRTUAL_RANGE:
1525 genInvokeVirtual(cUnit, mir);
1526 break;
1527
1528 case OP_INVOKE_SUPER:
1529 case OP_INVOKE_SUPER_RANGE:
1530 genInvokeSuper(cUnit, mir);
1531 break;
1532
1533 case OP_INVOKE_INTERFACE:
1534 case OP_INVOKE_INTERFACE_RANGE:
1535 genInvokeInterface(cUnit, mir);
1536 break;
1537
1538 case OP_NEG_INT:
1539 case OP_NOT_INT:
1540 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1541 break;
1542
1543 case OP_NEG_LONG:
1544 case OP_NOT_LONG:
1545 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1546 break;
1547
1548 case OP_NEG_FLOAT:
1549 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1550 break;
1551
1552 case OP_NEG_DOUBLE:
1553 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1554 break;
1555
1556 case OP_INT_TO_LONG:
1557 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1558 if (rlSrc[0].location == kLocPhysReg) {
1559 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1560 } else {
1561 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1562 }
1563 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1564 rlResult.lowReg, 31);
1565 storeValueWide(cUnit, rlDest, rlResult);
1566 break;
1567
1568 case OP_LONG_TO_INT:
1569 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1570 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1571 storeValue(cUnit, rlDest, rlSrc[0]);
1572 break;
1573
1574 case OP_INT_TO_BYTE:
1575 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1576 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1577 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1578 storeValue(cUnit, rlDest, rlResult);
1579 break;
1580
1581 case OP_INT_TO_SHORT:
1582 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1583 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1584 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1585 storeValue(cUnit, rlDest, rlResult);
1586 break;
1587
1588 case OP_INT_TO_CHAR:
1589 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1590 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1591 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1592 storeValue(cUnit, rlDest, rlResult);
1593 break;
1594
1595 case OP_INT_TO_FLOAT:
1596 case OP_INT_TO_DOUBLE:
1597 case OP_LONG_TO_FLOAT:
1598 case OP_LONG_TO_DOUBLE:
1599 case OP_FLOAT_TO_INT:
1600 case OP_FLOAT_TO_LONG:
1601 case OP_FLOAT_TO_DOUBLE:
1602 case OP_DOUBLE_TO_INT:
1603 case OP_DOUBLE_TO_LONG:
1604 case OP_DOUBLE_TO_FLOAT:
1605 genConversion(cUnit, mir);
1606 break;
1607
1608 case OP_ADD_INT:
1609 case OP_SUB_INT:
1610 case OP_MUL_INT:
1611 case OP_DIV_INT:
1612 case OP_REM_INT:
1613 case OP_AND_INT:
1614 case OP_OR_INT:
1615 case OP_XOR_INT:
1616 case OP_SHL_INT:
1617 case OP_SHR_INT:
1618 case OP_USHR_INT:
1619 case OP_ADD_INT_2ADDR:
1620 case OP_SUB_INT_2ADDR:
1621 case OP_MUL_INT_2ADDR:
1622 case OP_DIV_INT_2ADDR:
1623 case OP_REM_INT_2ADDR:
1624 case OP_AND_INT_2ADDR:
1625 case OP_OR_INT_2ADDR:
1626 case OP_XOR_INT_2ADDR:
1627 case OP_SHL_INT_2ADDR:
1628 case OP_SHR_INT_2ADDR:
1629 case OP_USHR_INT_2ADDR:
1630 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1631 break;
1632
1633 case OP_ADD_LONG:
1634 case OP_SUB_LONG:
1635 case OP_MUL_LONG:
1636 case OP_DIV_LONG:
1637 case OP_REM_LONG:
1638 case OP_AND_LONG:
1639 case OP_OR_LONG:
1640 case OP_XOR_LONG:
1641 case OP_ADD_LONG_2ADDR:
1642 case OP_SUB_LONG_2ADDR:
1643 case OP_MUL_LONG_2ADDR:
1644 case OP_DIV_LONG_2ADDR:
1645 case OP_REM_LONG_2ADDR:
1646 case OP_AND_LONG_2ADDR:
1647 case OP_OR_LONG_2ADDR:
1648 case OP_XOR_LONG_2ADDR:
1649 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1650 break;
1651
buzbee67bf8852011-08-17 17:51:35 -07001652 case OP_SHL_LONG:
1653 case OP_SHR_LONG:
1654 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001655 case OP_SHL_LONG_2ADDR:
1656 case OP_SHR_LONG_2ADDR:
1657 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001658 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1659 break;
1660
1661 case OP_ADD_FLOAT:
1662 case OP_SUB_FLOAT:
1663 case OP_MUL_FLOAT:
1664 case OP_DIV_FLOAT:
1665 case OP_REM_FLOAT:
1666 case OP_ADD_FLOAT_2ADDR:
1667 case OP_SUB_FLOAT_2ADDR:
1668 case OP_MUL_FLOAT_2ADDR:
1669 case OP_DIV_FLOAT_2ADDR:
1670 case OP_REM_FLOAT_2ADDR:
1671 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1672 break;
1673
1674 case OP_ADD_DOUBLE:
1675 case OP_SUB_DOUBLE:
1676 case OP_MUL_DOUBLE:
1677 case OP_DIV_DOUBLE:
1678 case OP_REM_DOUBLE:
1679 case OP_ADD_DOUBLE_2ADDR:
1680 case OP_SUB_DOUBLE_2ADDR:
1681 case OP_MUL_DOUBLE_2ADDR:
1682 case OP_DIV_DOUBLE_2ADDR:
1683 case OP_REM_DOUBLE_2ADDR:
1684 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1685 break;
1686
1687 case OP_RSUB_INT:
1688 case OP_ADD_INT_LIT16:
1689 case OP_MUL_INT_LIT16:
1690 case OP_DIV_INT_LIT16:
1691 case OP_REM_INT_LIT16:
1692 case OP_AND_INT_LIT16:
1693 case OP_OR_INT_LIT16:
1694 case OP_XOR_INT_LIT16:
1695 case OP_ADD_INT_LIT8:
1696 case OP_RSUB_INT_LIT8:
1697 case OP_MUL_INT_LIT8:
1698 case OP_DIV_INT_LIT8:
1699 case OP_REM_INT_LIT8:
1700 case OP_AND_INT_LIT8:
1701 case OP_OR_INT_LIT8:
1702 case OP_XOR_INT_LIT8:
1703 case OP_SHL_INT_LIT8:
1704 case OP_SHR_INT_LIT8:
1705 case OP_USHR_INT_LIT8:
1706 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1707 break;
1708
1709 default:
1710 res = true;
1711 }
1712 return res;
1713}
1714
1715static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1716 "kMirOpPhi",
1717 "kMirOpNullNRangeUpCheck",
1718 "kMirOpNullNRangeDownCheck",
1719 "kMirOpLowerBound",
1720 "kMirOpPunt",
1721 "kMirOpCheckInlinePrediction",
1722};
1723
1724/* Extended MIR instructions like PHI */
1725static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1726{
1727 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1728 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1729 strcpy(msg, extendedMIROpNames[opOffset]);
1730 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1731
1732 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1733 case kMirOpPhi: {
1734 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1735 op->flags.isNop = true;
1736 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1737 break;
1738 }
1739 default:
1740 break;
1741 }
1742}
1743
1744/* If there are any ins passed in registers that have not been promoted
1745 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001746 * Note: at this pointCopy any ins that are passed in register to their
1747 * home location */
buzbee67bf8852011-08-17 17:51:35 -07001748static void flushIns(CompilationUnit* cUnit)
1749{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001750 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001751 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001752 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1753 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001754 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001755 int startLoc = cUnit->method->NumRegisters() -
1756 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001757 for (int i = 0; i < inRegs; i++) {
1758 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001759 //TUNING: be smarter about flushing ins to frame
1760 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001761 if (loc.location == kLocPhysReg) {
1762 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001763 }
1764 }
1765
1766 // Handle special case of wide argument half in regs, half in frame
1767 if (inRegs == 3) {
1768 RegLocation loc = cUnit->regLocation[startLoc + 2];
1769 if (loc.wide && loc.location == kLocPhysReg) {
1770 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001771 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001772 inRegs++;
1773 }
1774 }
1775
1776 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001777 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001778 RegLocation loc = cUnit->regLocation[startLoc + i];
1779 if (loc.fpLocation == kLocPhysReg) {
1780 loc.location = kLocPhysReg;
1781 loc.fp = true;
1782 loc.lowReg = loc.fpLowReg;
1783 loc.highReg = loc.fpHighReg;
1784 }
1785 if (loc.location == kLocPhysReg) {
1786 if (loc.wide) {
1787 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1788 loc.lowReg, loc.highReg, INVALID_SREG);
1789 i++;
1790 } else {
buzbee561227c2011-09-02 15:28:19 -07001791 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001792 }
1793 }
1794 i++;
1795 }
1796}
1797
1798/* Handle the content in each basic block */
1799static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1800{
1801 MIR* mir;
1802 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1803 int blockId = bb->id;
1804
1805 cUnit->curBlock = bb;
1806 labelList[blockId].operands[0] = bb->startOffset;
1807
1808 /* Insert the block label */
1809 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1810 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1811
1812 oatClobberAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001813
1814 ArmLIR* headLIR = NULL;
1815
1816 if (bb->blockType == kEntryBlock) {
1817 /*
1818 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1819 * mechanism know so it doesn't try to use any of them when
1820 * expanding the frame or flushing. This leaves the utility
1821 * code with a single temp: r12. This should be enough.
1822 */
1823 oatLockTemp(cUnit, r0);
1824 oatLockTemp(cUnit, r1);
1825 oatLockTemp(cUnit, r2);
1826 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001827
1828 /*
1829 * We can safely skip the stack overflow check if we're
1830 * a leaf *and* our frame size < fudge factor.
1831 */
1832 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1833 ((size_t)cUnit->frameSize <
1834 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001835 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001836 if (!skipOverflowCheck) {
1837 /* Load stack limit */
1838 loadWordDisp(cUnit, rSELF,
1839 art::Thread::StackEndOffset().Int32Value(), r12);
1840 }
buzbee67bf8852011-08-17 17:51:35 -07001841 /* Spill core callee saves */
1842 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1843 /* Need to spill any FP regs? */
1844 if (cUnit->numFPSpills) {
1845 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1846 }
buzbeecefd1872011-09-09 09:59:52 -07001847 if (!skipOverflowCheck) {
1848 opRegRegImm(cUnit, kOpSub, rLR, rSP,
1849 cUnit->frameSize - (cUnit->numSpills * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001850 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1851 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001852 genRegCopy(cUnit, rSP, rLR); // Establish stack
1853 } else {
1854 opRegImm(cUnit, kOpSub, rSP,
1855 cUnit->frameSize - (cUnit->numSpills * 4));
1856 }
buzbee67bf8852011-08-17 17:51:35 -07001857 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1858 flushIns(cUnit);
1859 oatFreeTemp(cUnit, r0);
1860 oatFreeTemp(cUnit, r1);
1861 oatFreeTemp(cUnit, r2);
1862 oatFreeTemp(cUnit, r3);
1863 } else if (bb->blockType == kExitBlock) {
1864 newLIR0(cUnit, kArmPseudoMethodExit);
1865 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1866 /* Need to restore any FP callee saves? */
1867 if (cUnit->numFPSpills) {
1868 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1869 }
1870 if (cUnit->coreSpillMask & (1 << rLR)) {
1871 /* Unspill rLR to rPC */
1872 cUnit->coreSpillMask &= ~(1 << rLR);
1873 cUnit->coreSpillMask |= (1 << rPC);
1874 }
1875 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1876 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1877 /* We didn't pop to rPC, so must do a bv rLR */
1878 newLIR1(cUnit, kThumbBx, rLR);
1879 }
1880 }
1881
1882 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1883
1884 oatResetRegPool(cUnit);
buzbeef0cde542011-09-13 14:55:02 -07001885 oatClobberAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001886
1887 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1888 oatResetDefTracking(cUnit);
1889 }
1890
1891 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1892 handleExtendedMethodMIR(cUnit, mir);
1893 continue;
1894 }
1895
1896 cUnit->currentDalvikOffset = mir->offset;
1897
1898 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1899 InstructionFormat dalvikFormat =
1900 dexGetFormatFromOpcode(dalvikOpcode);
1901
1902 ArmLIR* boundaryLIR;
1903
1904 /* Mark the beginning of a Dalvik instruction for line tracking */
1905 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1906 (int) oatGetDalvikDisassembly(
1907 &mir->dalvikInsn, ""));
1908 /* Remember the first LIR for this block */
1909 if (headLIR == NULL) {
1910 headLIR = boundaryLIR;
1911 /* Set the first boundaryLIR as a scheduling barrier */
1912 headLIR->defMask = ENCODE_ALL;
1913 }
1914
1915 /* Don't generate the SSA annotation unless verbose mode is on */
1916 if (cUnit->printMe && mir->ssaRep) {
1917 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1918 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1919 }
1920
1921 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1922
1923 if (notHandled) {
1924 char buf[100];
1925 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1926 mir->offset,
1927 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1928 dalvikFormat);
1929 LOG(FATAL) << buf;
1930 }
1931 }
1932
1933 if (headLIR) {
1934 /*
1935 * Eliminate redundant loads/stores and delay stores into later
1936 * slots
1937 */
1938 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1939 cUnit->lastLIRInsn);
1940
1941 /*
1942 * Generate an unconditional branch to the fallthrough block.
1943 */
1944 if (bb->fallThrough) {
1945 genUnconditionalBranch(cUnit,
1946 &labelList[bb->fallThrough->id]);
1947 }
1948 }
1949 return false;
1950}
1951
1952/*
1953 * Nop any unconditional branches that go to the next instruction.
1954 * Note: new redundant branches may be inserted later, and we'll
1955 * use a check in final instruction assembly to nop those out.
1956 */
1957void removeRedundantBranches(CompilationUnit* cUnit)
1958{
1959 ArmLIR* thisLIR;
1960
1961 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1962 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1963 thisLIR = NEXT_LIR(thisLIR)) {
1964
1965 /* Branch to the next instruction */
1966 if ((thisLIR->opcode == kThumbBUncond) ||
1967 (thisLIR->opcode == kThumb2BUncond)) {
1968 ArmLIR* nextLIR = thisLIR;
1969
1970 while (true) {
1971 nextLIR = NEXT_LIR(nextLIR);
1972
1973 /*
1974 * Is the branch target the next instruction?
1975 */
1976 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1977 thisLIR->flags.isNop = true;
1978 break;
1979 }
1980
1981 /*
1982 * Found real useful stuff between the branch and the target.
1983 * Need to explicitly check the lastLIRInsn here because it
1984 * might be the last real instruction.
1985 */
1986 if (!isPseudoOpcode(nextLIR->opcode) ||
1987 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1988 break;
1989 }
1990 }
1991 }
1992}
1993
buzbee5ade1d22011-09-09 14:44:52 -07001994static void handleThrowLaunchpads(CompilationUnit *cUnit)
1995{
1996 ArmLIR** throwLabel =
1997 (ArmLIR **) cUnit->throwLaunchpads.elemList;
1998 int numElems = cUnit->throwLaunchpads.numUsed;
1999 int i;
2000
2001 for (i = 0; i < numElems; i++) {
2002 ArmLIR* lab = throwLabel[i];
2003 cUnit->currentDalvikOffset = lab->operands[1];
2004 oatAppendLIR(cUnit, (LIR *)lab);
2005 int funcOffset = 0;
2006 int v1 = lab->operands[2];
2007 int v2 = lab->operands[3];
2008 switch(lab->operands[0]) {
2009 case kArmThrowNullPointer:
2010 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2011 break;
2012 case kArmThrowArrayBounds:
2013 if (v2 != r0) {
2014 genRegCopy(cUnit, r0, v1);
2015 genRegCopy(cUnit, r1, v2);
2016 } else {
2017 if (v1 == r1) {
2018 genRegCopy(cUnit, r12, v1);
2019 genRegCopy(cUnit, r1, v2);
2020 genRegCopy(cUnit, r0, r12);
2021 } else {
2022 genRegCopy(cUnit, r1, v2);
2023 genRegCopy(cUnit, r0, v1);
2024 }
2025 }
2026 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2027 break;
2028 case kArmThrowDivZero:
2029 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2030 break;
2031 case kArmThrowVerificationError:
2032 loadConstant(cUnit, r0, v1);
2033 loadConstant(cUnit, r1, v2);
2034 funcOffset =
2035 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2036 break;
2037 case kArmThrowNegArraySize:
2038 genRegCopy(cUnit, r0, v1);
2039 funcOffset =
2040 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2041 break;
2042 case kArmThrowInternalError:
2043 genRegCopy(cUnit, r0, v1);
2044 funcOffset =
2045 OFFSETOF_MEMBER(Thread, pThrowInternalErrorFromCode);
2046 break;
2047 case kArmThrowRuntimeException:
2048 genRegCopy(cUnit, r0, v1);
2049 funcOffset =
2050 OFFSETOF_MEMBER(Thread, pThrowRuntimeExceptionFromCode);
2051 break;
2052 case kArmThrowNoSuchMethod:
2053 genRegCopy(cUnit, r0, v1);
2054 funcOffset =
2055 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2056 break;
buzbeeec5adf32011-09-11 15:25:43 -07002057 case kArmThrowStackOverflow:
2058 funcOffset =
2059 OFFSETOF_MEMBER(Thread, pStackOverflowFromCode);
2060 // Restore stack alignment
2061 opRegImm(cUnit, kOpAdd, rSP, cUnit->numSpills * 4);
2062 break;
buzbee5ade1d22011-09-09 14:44:52 -07002063 default:
2064 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2065 }
2066 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
buzbeeec5adf32011-09-11 15:25:43 -07002067 callUnwindableHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002068 }
2069}
2070
buzbee67bf8852011-08-17 17:51:35 -07002071void oatMethodMIR2LIR(CompilationUnit* cUnit)
2072{
2073 /* Used to hold the labels of each block */
2074 cUnit->blockLabelList =
2075 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2076
2077 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2078 kPreOrderDFSTraversal, false /* Iterative */);
2079 removeRedundantBranches(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002080
2081 handleThrowLaunchpads(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002082}
2083
2084/* Common initialization routine for an architecture family */
2085bool oatArchInit()
2086{
2087 int i;
2088
2089 for (i = 0; i < kArmLast; i++) {
2090 if (EncodingMap[i].opcode != i) {
2091 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2092 " is wrong: expecting " << i << ", seeing " <<
2093 (int)EncodingMap[i].opcode;
2094 }
2095 }
2096
2097 return oatArchVariantInit();
2098}
2099
2100/* Needed by the Assembler */
2101void oatSetupResourceMasks(ArmLIR* lir)
2102{
2103 setupResourceMasks(lir);
2104}
2105
2106/* Needed by the ld/st optmizatons */
2107ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2108{
2109 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2110}
2111
2112/* Needed by the register allocator */
2113ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2114{
2115 return genRegCopy(cUnit, rDest, rSrc);
2116}
2117
2118/* Needed by the register allocator */
2119void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2120 int srcLo, int srcHi)
2121{
2122 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2123}
2124
2125void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2126 int displacement, int rSrc, OpSize size)
2127{
2128 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2129}
2130
2131void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2132 int displacement, int rSrcLo, int rSrcHi)
2133{
2134 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2135}