blob: 44cbc0ead9382d4d87bd04157310f65e6819b475 [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
buzbee0c7f26d2011-09-07 12:28:51 -070017#define FORCE_SLOW 0
buzbee2a475e72011-09-07 17:19:17 -070018#define DISPLAY_MISSING_TARGETS
buzbeee9a72f62011-09-04 17:59:07 -070019
buzbee67bf8852011-08-17 17:51:35 -070020static const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
21 INVALID_REG, INVALID_SREG, 0,
22 kLocDalvikFrame, INVALID_REG, INVALID_REG,
23 INVALID_OFFSET};
24static const RegLocation retLoc = LOC_DALVIK_RETURN_VAL;
25static const RegLocation retLocWide = LOC_DALVIK_RETURN_VAL_WIDE;
26
buzbeedfd3d702011-08-28 12:56:51 -070027/*
28 * Let helper function take care of everything. Will call
29 * Array::AllocFromCode(type_idx, method, count);
30 * Note: AllocFromCode will handle checks for errNegativeArraySize.
31 */
buzbee67bf8852011-08-17 17:51:35 -070032static void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
33 RegLocation rlSrc)
34{
buzbeedfd3d702011-08-28 12:56:51 -070035 oatFlushAllRegs(cUnit); /* Everything to home location */
36 loadWordDisp(cUnit, rSELF,
37 OFFSETOF_MEMBER(Thread, pAllocFromCode), rLR);
38 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
39 loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
40 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
41 opReg(cUnit, kOpBlx, rLR);
42 oatClobberCallRegs(cUnit);
43 RegLocation rlResult = oatGetReturn(cUnit);
44 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070045}
46
47/*
48 * Similar to genNewArray, but with post-allocation initialization.
49 * Verifier guarantees we're dealing with an array class. Current
50 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
51 * Current code also throws internal unimp if not 'L', '[' or 'I'.
52 */
53static void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
54{
55 DecodedInstruction* dInsn = &mir->dalvikInsn;
56 int elems;
buzbeedfd3d702011-08-28 12:56:51 -070057 int typeId;
buzbee67bf8852011-08-17 17:51:35 -070058 if (isRange) {
59 elems = dInsn->vA;
buzbeedfd3d702011-08-28 12:56:51 -070060 typeId = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -070061 } else {
62 elems = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070063 typeId = dInsn->vC;
buzbee67bf8852011-08-17 17:51:35 -070064 }
buzbeedfd3d702011-08-28 12:56:51 -070065 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070066 loadWordDisp(cUnit, rSELF,
buzbee1da522d2011-09-04 11:22:20 -070067 OFFSETOF_MEMBER(Thread, pCheckAndAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070068 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
69 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
70 loadConstant(cUnit, r2, elems); // arg2 <- count
71 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -070072 /*
buzbeedfd3d702011-08-28 12:56:51 -070073 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
74 * return region. Because AllocFromCode placed the new array
75 * in r0, we'll just lock it into place. When debugger support is
76 * added, it may be necessary to additionally copy all return
77 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070078 */
buzbee67bf8852011-08-17 17:51:35 -070079 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070080
buzbee67bf8852011-08-17 17:51:35 -070081 // Having a range of 0 is legal
82 if (isRange && (dInsn->vA > 0)) {
83 /*
84 * Bit of ugliness here. We're going generate a mem copy loop
85 * on the register range, but it is possible that some regs
86 * in the range have been promoted. This is unlikely, but
87 * before generating the copy, we'll just force a flush
88 * of any regs in the source range that have been promoted to
89 * home location.
90 */
91 for (unsigned int i = 0; i < dInsn->vA; i++) {
92 RegLocation loc = oatUpdateLoc(cUnit,
93 oatGetSrc(cUnit, mir, i));
94 if (loc.location == kLocPhysReg) {
95 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
96 }
97 }
98 /*
99 * TUNING note: generated code here could be much improved, but
100 * this is an uncommon operation and isn't especially performance
101 * critical.
102 */
103 int rSrc = oatAllocTemp(cUnit);
104 int rDst = oatAllocTemp(cUnit);
105 int rIdx = oatAllocTemp(cUnit);
106 int rVal = rLR; // Using a lot of temps, rLR is known free here
107 // Set up source pointer
108 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
109 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
110 // Set up the target pointer
111 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700112 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700113 // Set up the loop counter (known to be > 0)
114 loadConstant(cUnit, rIdx, dInsn->vA);
115 // Generate the copy loop. Going backwards for convenience
116 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
117 target->defMask = ENCODE_ALL;
118 // Copy next element
119 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
120 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
121 // Use setflags encoding here
122 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
123 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
124 branch->generic.target = (LIR*)target;
125 } else if (!isRange) {
126 // TUNING: interleave
127 for (unsigned int i = 0; i < dInsn->vA; i++) {
128 RegLocation rlArg = loadValue(cUnit,
129 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700130 storeBaseDisp(cUnit, r0,
131 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700132 i * 4, rlArg.lowReg, kWord);
133 // If the loadValue caused a temp to be allocated, free it
134 if (oatIsTemp(cUnit, rlArg.lowReg)) {
135 oatFreeTemp(cUnit, rlArg.lowReg);
136 }
137 }
138 }
139}
140
141static void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
142{
buzbeee1931742011-08-28 21:15:53 -0700143 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
144 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700145 int fieldIdx = mir->dalvikInsn.vB;
146 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
147 if (field == NULL) {
148 // Slow path
149 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
150 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700151 oatFlushAllRegs(cUnit);
152 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
153 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
154 loadCurrMethodDirect(cUnit, r1);
155 loadValueDirect(cUnit, rlSrc, r2);
156 opReg(cUnit, kOpBlx, rLR);
157 oatClobberCallRegs(cUnit);
158 } else {
buzbee1da522d2011-09-04 11:22:20 -0700159 // fast path
160 int fieldOffset = field->GetOffset().Int32Value();
161 art::ClassLinker* class_linker = art::Runtime::Current()->
162 GetClassLinker();
163 const art::DexFile& dex_file = class_linker->
164 FindDexFile(field->GetDeclaringClass()->GetDexCache());
165 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
166 int typeIdx = field_id.class_idx_;
167 // Using fixed register to sync with slow path
168 int rMethod = r1;
169 oatLockTemp(cUnit, rMethod);
170 loadCurrMethodDirect(cUnit, rMethod);
171 int rBase = r0;
172 oatLockTemp(cUnit, rBase);
173 loadWordDisp(cUnit, rMethod,
174 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
175 rBase);
176 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
177 sizeof(int32_t*)* typeIdx, rBase);
178 // TUNING: fast path should fall through
179 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
180 loadWordDisp(cUnit, rSELF,
181 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
182 loadConstant(cUnit, r0, typeIdx);
183 opReg(cUnit, kOpBlx, rLR);
184 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
185 skipTarget->defMask = ENCODE_ALL;
186 branchOver->generic.target = (LIR*)skipTarget;
187 rlSrc = oatGetSrc(cUnit, mir, 0);
188 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
189 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700190#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700191 if (field->IsVolatile()) {
192 oatGenMemBarrier(cUnit, kSY);
193 }
buzbee67bf8852011-08-17 17:51:35 -0700194#endif
buzbee1da522d2011-09-04 11:22:20 -0700195 if (isObject) {
196 markGCCard(cUnit, rlSrc.lowReg, rBase);
197 }
198 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700199 }
buzbee67bf8852011-08-17 17:51:35 -0700200}
201
202static void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
203{
buzbee1da522d2011-09-04 11:22:20 -0700204 int fieldIdx = mir->dalvikInsn.vB;
205 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee9a72f62011-09-04 17:59:07 -0700206 if (FORCE_SLOW || field == NULL) {
buzbeee1931742011-08-28 21:15:53 -0700207 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700208 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700209 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
210 loadCurrMethodDirect(cUnit, r1);
211 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
212 opReg(cUnit, kOpBlx, rLR);
213 oatClobberCallRegs(cUnit);
214 } else {
buzbee1da522d2011-09-04 11:22:20 -0700215 // fast path
216 int fieldOffset = field->GetOffset().Int32Value();
217 art::ClassLinker* class_linker = art::Runtime::Current()->
218 GetClassLinker();
219 const art::DexFile& dex_file = class_linker->
220 FindDexFile(field->GetDeclaringClass()->GetDexCache());
221 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
222 int typeIdx = field_id.class_idx_;
223 // Using fixed register to sync with slow path
224 int rMethod = r1;
225 oatLockTemp(cUnit, rMethod);
226 loadCurrMethodDirect(cUnit, r1);
227 int rBase = r0;
228 oatLockTemp(cUnit, rBase);
229 loadWordDisp(cUnit, rMethod,
230 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
231 rBase);
232 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
233 sizeof(int32_t*)* typeIdx, rBase);
234 // TUNING: fast path should fall through
235 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
236 loadWordDisp(cUnit, rSELF,
237 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
238 loadConstant(cUnit, r0, typeIdx);
239 opReg(cUnit, kOpBlx, rLR);
240 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
241 skipTarget->defMask = ENCODE_ALL;
242 branchOver->generic.target = (LIR*)skipTarget;
243 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
244 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
245 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
246 rlSrc.highReg);
247#if ANDROID_SMP != 0
248 if (field->IsVolatile()) {
249 oatGenMemBarrier(cUnit, kSY);
250 }
buzbeec143c552011-08-20 17:38:58 -0700251#endif
buzbee1da522d2011-09-04 11:22:20 -0700252 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700253 }
buzbee67bf8852011-08-17 17:51:35 -0700254}
255
256
buzbee67bf8852011-08-17 17:51:35 -0700257static void genSgetWide(CompilationUnit* cUnit, MIR* mir,
258 RegLocation rlResult, RegLocation rlDest)
259{
buzbee1da522d2011-09-04 11:22:20 -0700260 int fieldIdx = mir->dalvikInsn.vB;
261 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee9a72f62011-09-04 17:59:07 -0700262 if (FORCE_SLOW || field == NULL) {
buzbeee1931742011-08-28 21:15:53 -0700263 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700264 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700265 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
266 loadCurrMethodDirect(cUnit, r1);
267 opReg(cUnit, kOpBlx, rLR);
268 RegLocation rlResult = oatGetReturnWide(cUnit);
269 storeValueWide(cUnit, rlDest, rlResult);
270 } else {
buzbee1da522d2011-09-04 11:22:20 -0700271 // Fast path
272 int fieldOffset = field->GetOffset().Int32Value();
273 art::ClassLinker* class_linker = art::Runtime::Current()->
274 GetClassLinker();
275 const art::DexFile& dex_file = class_linker->
276 FindDexFile(field->GetDeclaringClass()->GetDexCache());
277 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
278 int typeIdx = field_id.class_idx_;
279 // Using fixed register to sync with slow path
280 int rMethod = r1;
281 oatLockTemp(cUnit, rMethod);
282 loadCurrMethodDirect(cUnit, rMethod);
283 int rBase = r0;
284 oatLockTemp(cUnit, rBase);
285 loadWordDisp(cUnit, rMethod,
286 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
287 rBase);
288 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
289 sizeof(int32_t*)* typeIdx, rBase);
290 // TUNING: fast path should fall through
291 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
292 loadWordDisp(cUnit, rSELF,
293 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
294 loadConstant(cUnit, r0, typeIdx);
295 opReg(cUnit, kOpBlx, rLR);
296 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
297 skipTarget->defMask = ENCODE_ALL;
298 branchOver->generic.target = (LIR*)skipTarget;
299 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
300 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
301#if ANDROID_SMP != 0
302 if (isVolatile) {
303 oatGenMemBarrier(cUnit, kSY);
304 }
buzbeec143c552011-08-20 17:38:58 -0700305#endif
buzbee1da522d2011-09-04 11:22:20 -0700306 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
307 rlResult.highReg, INVALID_SREG);
308 oatFreeTemp(cUnit, rBase);
309 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700310 }
buzbee67bf8852011-08-17 17:51:35 -0700311}
312
313static void genSget(CompilationUnit* cUnit, MIR* mir,
314 RegLocation rlResult, RegLocation rlDest)
315{
buzbee1da522d2011-09-04 11:22:20 -0700316 int fieldIdx = mir->dalvikInsn.vB;
317 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee1931742011-08-28 21:15:53 -0700318 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
319 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbeee9a72f62011-09-04 17:59:07 -0700320 if (FORCE_SLOW || field == NULL) {
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);
328 opReg(cUnit, kOpBlx, rLR);
329 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->
337 FindDexFile(field->GetDeclaringClass()->GetDexCache());
338 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);
356 opReg(cUnit, kOpBlx, rLR);
357 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
buzbee1da522d2011-09-04 11:22:20 -0700363 if (isVolatile) {
364 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]
434 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
435 // 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);
487 newLIR1(cUnit, kThumbBlxR, rLR);
488 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]
503 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
504 // 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]
597 genNullCheck(cUnit, oatSSASrc(mir,0), r1,
598 mir->offset, NULL);
buzbee4a3164f2011-09-03 11:25:10 -0700599 break;
600 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
601 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
602 rLR);
603 break;
604 case 2: // Get ...->super_class_->vtable [u/s rLR]
605 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
606 break;
607 case 3: // Get target method [use rLR, set r0]
608 loadWordDisp(cUnit, rLR, (target_idx * 4) +
609 art::Array::DataOffset().Int32Value(), r0);
610 break;
611 case 4: // Get the target compiled code address [uses r0, sets rLR]
612 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
613 break;
buzbee67bf8852011-08-17 17:51:35 -0700614 default:
615 return -1;
616 }
buzbee4a3164f2011-09-03 11:25:10 -0700617 return state + 1;
618}
619
620/* Slow-path version of nextSuperCallInsn */
621static int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
622 DecodedInstruction* dInsn, int state,
623 ArmLIR* rollback)
624{
625 DCHECK(rollback != NULL);
626 RegLocation rlArg;
627 ArmLIR* skipBranch;
628 ArmLIR* skipTarget;
629 int tReg;
630 /*
631 * This handles the case in which the base method is not fully
632 * resolved at compile time. We must generate code to test
633 * for resolution a run time, bail to the slow path if not to
634 * fill in all the tables. In the latter case, we'll restart at
635 * at the beginning of the sequence.
636 */
637 switch(state) {
638 case 0: // Get the current Method* [sets r0]
639 loadCurrMethodDirect(cUnit, r0);
640 break;
641 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
642 loadWordDisp(cUnit, r0,
643 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
644 break;
645 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
646 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
647 art::Array::DataOffset().Int32Value(), rLR);
648 break;
649 case 3: // Resolved?
650 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
651 // Slowest path, bail to helper, rollback and retry
652 loadWordDisp(cUnit, rSELF,
653 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
654 loadConstant(cUnit, r1, dInsn->vB);
655 newLIR1(cUnit, kThumbBlxR, rLR);
656 genUnconditionalBranch(cUnit, rollback);
657 // Resume normal slow path
658 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
659 skipTarget->defMask = ENCODE_ALL;
660 skipBranch->generic.target = (LIR*)skipTarget;
661 // Get base_method->method_index [usr rLR, set rLR]
662 loadBaseDisp(cUnit, mir, rLR,
663 Method::GetMethodIndexOffset().Int32Value(), rLR,
664 kUnsignedHalf, INVALID_SREG);
665 // Load "this" [set r1]
666 rlArg = oatGetSrc(cUnit, mir, 0);
667 loadValueDirectFixed(cUnit, rlArg, r1);
668 // Load curMethod->declaring_class_ [uses r0, sets r0]
669 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
670 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700671 // Null this?
672 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
673 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700674 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
675 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700676 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700677 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee4a3164f2011-09-03 11:25:10 -0700678 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
679 // Range check, throw NSM on failure
680 tReg = oatAllocTemp(cUnit);
681 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
682 tReg);
683 genBoundsCheck(cUnit, tReg, rLR, mir->offset, NULL);
684 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;
buzbeee9a72f62011-09-04 17:59:07 -0700728 rlArg = oatUpdateLoc(cUnit, oatGetSrc(cUnit, mir, i));
buzbee67bf8852011-08-17 17:51:35 -0700729 if (rlArg.location == kLocPhysReg) {
730 reg = rlArg.lowReg;
731 } else {
buzbee109bd6a2011-09-06 13:58:41 -0700732 // r3 is the last arg register loaded, so can safely be used here
733 reg = r3;
734 loadValueDirectFixed(cUnit, rlArg, reg);
buzbee561227c2011-09-02 15:28:19 -0700735 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700736 }
737 storeBaseDisp(cUnit, rSP, (i + 1) * 4, reg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700738 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700739 }
740
741 /* Load register arguments r1..r3 */
buzbeee9a72f62011-09-04 17:59:07 -0700742 for (unsigned int i = 0; i < 3; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700743 if (i < dInsn->vA)
744 registerArgs[i] = (isRange) ? dInsn->vC + i : i;
745 else
746 registerArgs[i] = INVALID_REG;
747 }
buzbeee9a72f62011-09-04 17:59:07 -0700748 if (skipThis) {
749 registerArgs[0] = INVALID_REG;
750 }
buzbee67bf8852011-08-17 17:51:35 -0700751 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
buzbee561227c2011-09-02 15:28:19 -0700752 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700753
buzbee6a0f7f52011-09-05 16:14:20 -0700754 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700755 // Load direct & need a "this" null check?
756 if (pcrLabel) {
757 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1,
758 mir->offset, NULL);
759 }
760 return callState;
761}
762
763/*
764 * May have 0+ arguments (also used for jumbo). Note that
765 * source virtual registers may be in physical registers, so may
766 * need to be flushed to home location before copying. This
767 * applies to arg3 and above (see below).
768 *
769 * Two general strategies:
770 * If < 20 arguments
771 * Pass args 3-18 using vldm/vstm block copy
772 * Pass arg0, arg1 & arg2 in r1-r3
773 * If 20+ arguments
774 * Pass args arg19+ using memcpy block copy
775 * Pass arg0, arg1 & arg2 in r1-r3
776 *
777 */
778static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
779 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700780 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700781 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700782{
783 int firstArg = dInsn->vC;
784 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700785 int registerArgs[3];
786
buzbee67bf8852011-08-17 17:51:35 -0700787 // If we can treat it as non-range (Jumbo ops will use range form)
788 if (numArgs <= 5)
789 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700790 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700791 /*
792 * Make sure range list doesn't span the break between in normal
793 * Dalvik vRegs and the ins.
794 */
buzbee1b4c8592011-08-31 10:43:51 -0700795 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700796 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700797 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
798 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700799 }
800
801 /*
802 * First load the non-register arguments. Both forms expect all
803 * of the source arguments to be in their home frame location, so
804 * scan the sReg names and flush any that have been promoted to
805 * frame backing storage.
806 */
807 // Scan the rest of the args - if in physReg flush to memory
buzbee0c7f26d2011-09-07 12:28:51 -0700808 for (int i = 3; i < numArgs; i++) {
buzbeee9a72f62011-09-04 17:59:07 -0700809 RegLocation loc = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700810 if (loc.wide) {
811 loc = oatUpdateLocWide(cUnit, loc);
812 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
813 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
814 loc.highReg);
buzbee561227c2011-09-02 15:28:19 -0700815 callState = nextCallInsn(cUnit, mir, dInsn, callState,
816 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700817 }
818 } else {
819 loc = oatUpdateLoc(cUnit, loc);
820 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
821 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700822 callState = nextCallInsn(cUnit, mir, dInsn, callState,
823 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700824 }
buzbee67bf8852011-08-17 17:51:35 -0700825 }
826 }
827
828 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
829 int outsOffset = 4 /* Method* */ + (3 * 4);
830 if (numArgs >= 20) {
831 // Generate memcpy, but first make sure all of
832 opRegRegImm(cUnit, kOpAdd, r0, rSP, startOffset);
833 opRegRegImm(cUnit, kOpAdd, r1, rSP, outsOffset);
834 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
835 loadConstant(cUnit, r2, (numArgs - 3) * 4);
836 newLIR1(cUnit, kThumbBlxR, rLR);
837 } else {
838 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700839 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700840 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700841 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbee1b4c8592011-08-31 10:43:51 -0700842 newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
buzbee561227c2011-09-02 15:28:19 -0700843 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700844 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700845 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700846 newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
buzbee561227c2011-09-02 15:28:19 -0700847 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700848 }
849
850 // Handle the 1st 3 in r1, r2 & r3
buzbeee9a72f62011-09-04 17:59:07 -0700851 for (unsigned int i = 0; i < 3; i++) {
852 if (i < dInsn->vA)
853 registerArgs[i] = dInsn->vC + i;
854 else
855 registerArgs[i] = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700856 }
buzbeee9a72f62011-09-04 17:59:07 -0700857 if (skipThis) {
858 registerArgs[0] = INVALID_REG;
859 }
860 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
861 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700862
buzbee561227c2011-09-02 15:28:19 -0700863 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700864 return callState;
865}
866
buzbee2a475e72011-09-07 17:19:17 -0700867#ifdef DISPLAY_MISSING_TARGETS
868// Debugging routine - if null target, branch to DebugMe
869static void genShowTarget(CompilationUnit* cUnit)
870{
871 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
872 loadWordDisp(cUnit, rSELF,
873 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
874 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
875 target->defMask = -1;
876 branchOver->generic.target = (LIR*)target;
877}
878#endif
879
buzbee561227c2011-09-02 15:28:19 -0700880static void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
881 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700882{
883 DecodedInstruction* dInsn = &mir->dalvikInsn;
884 int callState = 0;
885 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700886 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700887 NextCallInsn nextCallInsn = nextSDCallInsn;
888
buzbee109bd6a2011-09-06 13:58:41 -0700889 // Explicit register usage
890 oatLockCallTemps(cUnit);
891
buzbee561227c2011-09-02 15:28:19 -0700892 if (range) {
893 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700894 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700895 } else {
896 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700897 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700898 }
buzbee67bf8852011-08-17 17:51:35 -0700899 // Finish up any of the call sequence not interleaved in arg loading
900 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700901 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700902 }
buzbee2a475e72011-09-07 17:19:17 -0700903#ifdef DISPLAY_MISSING_TARGETS
904 genShowTarget(cUnit);
905#endif
buzbee67bf8852011-08-17 17:51:35 -0700906 newLIR1(cUnit, kThumbBlxR, rLR);
907}
908
buzbee4a3164f2011-09-03 11:25:10 -0700909/*
910 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
911 * which will locate the target and continue on via a tail call.
912 */
buzbee67bf8852011-08-17 17:51:35 -0700913static void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
914{
915 DecodedInstruction* dInsn = &mir->dalvikInsn;
916 int callState = 0;
917 ArmLIR* nullCk;
buzbee109bd6a2011-09-06 13:58:41 -0700918
919 // Explicit register usage
920 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700921 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700922 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700923 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
924 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700925 false, nextInterfaceCallInsn, NULL,
926 true);
buzbee67bf8852011-08-17 17:51:35 -0700927 else
928 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700929 nextInterfaceCallInsn, NULL, true);
buzbee67bf8852011-08-17 17:51:35 -0700930 // Finish up any of the call sequence not interleaved in arg loading
931 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700932 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700933 }
buzbee2a475e72011-09-07 17:19:17 -0700934#ifdef DISPLAY_MISSING_TARGETS
935 genShowTarget(cUnit);
936#endif
buzbee67bf8852011-08-17 17:51:35 -0700937 newLIR1(cUnit, kThumbBlxR, rLR);
938}
939
940static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
941{
942 DecodedInstruction* dInsn = &mir->dalvikInsn;
943 int callState = 0;
944 ArmLIR* nullCk;
buzbee4a3164f2011-09-03 11:25:10 -0700945 ArmLIR* rollback;
946 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
947 Get(dInsn->vB);
948 NextCallInsn nextCallInsn;
949 bool fastPath = true;
buzbee109bd6a2011-09-06 13:58:41 -0700950
951 // Explicit register usage
952 oatLockCallTemps(cUnit);
buzbee6a0f7f52011-09-05 16:14:20 -0700953 if (FORCE_SLOW || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -0700954 fastPath = false;
955 } else {
956 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
957 if (superClass == NULL) {
958 fastPath = false;
959 } else {
960 int32_t target_idx = baseMethod->GetMethodIndex();
961 if (superClass->GetVTable()->GetLength() <= target_idx) {
962 fastPath = false;
963 } else {
964 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
965 }
966 }
967 }
968 if (fastPath) {
969 nextCallInsn = nextSuperCallInsn;
970 rollback = NULL;
971 } else {
972 nextCallInsn = nextSuperCallInsnSP;
973 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
974 rollback->defMask = -1;
975 }
buzbee67bf8852011-08-17 17:51:35 -0700976 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
977 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700978 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700979 else
980 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700981 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700982 // Finish up any of the call sequence not interleaved in arg loading
983 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -0700984 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700985 }
buzbee2a475e72011-09-07 17:19:17 -0700986#ifdef DISPLAY_MISSING_TARGETS
987 genShowTarget(cUnit);
988#endif
buzbee67bf8852011-08-17 17:51:35 -0700989 newLIR1(cUnit, kThumbBlxR, rLR);
990}
991
992static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
993{
994 DecodedInstruction* dInsn = &mir->dalvikInsn;
995 int callState = 0;
996 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700997 ArmLIR* rollback;
998 Method* method = cUnit->method->GetDexCacheResolvedMethods()->
999 Get(dInsn->vB);
1000 NextCallInsn nextCallInsn;
buzbee7b1b86d2011-08-26 18:59:10 -07001001
buzbee109bd6a2011-09-06 13:58:41 -07001002 // Explicit register usage
1003 oatLockCallTemps(cUnit);
buzbeee9a72f62011-09-04 17:59:07 -07001004 if (FORCE_SLOW || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001005 // Slow path
1006 nextCallInsn = nextVCallInsnSP;
1007 // If we need a slow-path callout, we'll restart here
1008 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1009 rollback->defMask = -1;
1010 } else {
1011 // Fast path
1012 nextCallInsn = nextVCallInsn;
1013 rollback = NULL;
1014 }
buzbee67bf8852011-08-17 17:51:35 -07001015 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
1016 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001017 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001018 else
1019 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001020 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001021 // Finish up any of the call sequence not interleaved in arg loading
1022 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001023 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001024 }
buzbee2a475e72011-09-07 17:19:17 -07001025#ifdef DISPLAY_MISSING_TARGETS
1026 genShowTarget(cUnit);
1027#endif
buzbee67bf8852011-08-17 17:51:35 -07001028 newLIR1(cUnit, kThumbBlxR, rLR);
1029}
1030
buzbee67bf8852011-08-17 17:51:35 -07001031static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
1032 BasicBlock* bb, ArmLIR* labelList)
1033{
1034 bool res = false; // Assume success
1035 RegLocation rlSrc[3];
1036 RegLocation rlDest = badLoc;
1037 RegLocation rlResult = badLoc;
1038 Opcode opcode = mir->dalvikInsn.opcode;
1039
1040 /* Prep Src and Dest locations */
1041 int nextSreg = 0;
1042 int nextLoc = 0;
1043 int attrs = oatDataFlowAttributes[opcode];
1044 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1045 if (attrs & DF_UA) {
1046 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1047 nextSreg++;
1048 } else if (attrs & DF_UA_WIDE) {
1049 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1050 nextSreg + 1);
1051 nextSreg+= 2;
1052 }
1053 if (attrs & DF_UB) {
1054 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1055 nextSreg++;
1056 } else if (attrs & DF_UB_WIDE) {
1057 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1058 nextSreg + 1);
1059 nextSreg+= 2;
1060 }
1061 if (attrs & DF_UC) {
1062 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1063 } else if (attrs & DF_UC_WIDE) {
1064 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1065 nextSreg + 1);
1066 }
1067 if (attrs & DF_DA) {
1068 rlDest = oatGetDest(cUnit, mir, 0);
1069 } else if (attrs & DF_DA_WIDE) {
1070 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1071 }
1072
1073 switch(opcode) {
1074 case OP_NOP:
1075 break;
1076
1077 case OP_MOVE_EXCEPTION:
1078 int exOffset;
1079 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001080 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001081 resetReg = oatAllocTemp(cUnit);
1082 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1083 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1084 loadConstant(cUnit, resetReg, 0);
1085 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1086 storeValue(cUnit, rlDest, rlResult);
1087 break;
1088
1089 case OP_RETURN_VOID:
1090 break;
1091
1092 case OP_RETURN:
1093 case OP_RETURN_OBJECT:
1094 storeValue(cUnit, retLoc, rlSrc[0]);
1095 break;
1096
1097 case OP_RETURN_WIDE:
1098 rlDest = retLocWide;
1099 rlDest.fp = rlSrc[0].fp;
1100 storeValueWide(cUnit, rlDest, rlSrc[0]);
1101 break;
1102
1103 case OP_MOVE_RESULT_WIDE:
1104 if (mir->OptimizationFlags & MIR_INLINED)
1105 break; // Nop - combined w/ previous invoke
1106 /*
1107 * Somewhat hacky here. Because we're now passing
1108 * return values in registers, we have to let the
1109 * register allocation utilities know that the return
1110 * registers are live and may not be used for address
1111 * formation in storeValueWide.
1112 */
1113 assert(retLocWide.lowReg == r0);
buzbee1da522d2011-09-04 11:22:20 -07001114 assert(retLocWide.highReg == r1);
buzbee67bf8852011-08-17 17:51:35 -07001115 oatLockTemp(cUnit, retLocWide.lowReg);
1116 oatLockTemp(cUnit, retLocWide.highReg);
1117 storeValueWide(cUnit, rlDest, retLocWide);
1118 oatFreeTemp(cUnit, retLocWide.lowReg);
1119 oatFreeTemp(cUnit, retLocWide.highReg);
1120 break;
1121
1122 case OP_MOVE_RESULT:
1123 case OP_MOVE_RESULT_OBJECT:
1124 if (mir->OptimizationFlags & MIR_INLINED)
1125 break; // Nop - combined w/ previous invoke
1126 /* See comment for OP_MOVE_RESULT_WIDE */
1127 assert(retLoc.lowReg == r0);
1128 oatLockTemp(cUnit, retLoc.lowReg);
1129 storeValue(cUnit, rlDest, retLoc);
1130 oatFreeTemp(cUnit, retLoc.lowReg);
1131 break;
1132
1133 case OP_MOVE:
1134 case OP_MOVE_OBJECT:
1135 case OP_MOVE_16:
1136 case OP_MOVE_OBJECT_16:
1137 case OP_MOVE_FROM16:
1138 case OP_MOVE_OBJECT_FROM16:
1139 storeValue(cUnit, rlDest, rlSrc[0]);
1140 break;
1141
1142 case OP_MOVE_WIDE:
1143 case OP_MOVE_WIDE_16:
1144 case OP_MOVE_WIDE_FROM16:
1145 storeValueWide(cUnit, rlDest, rlSrc[0]);
1146 break;
1147
1148 case OP_CONST:
1149 case OP_CONST_4:
1150 case OP_CONST_16:
1151 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1152 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1153 storeValue(cUnit, rlDest, rlResult);
1154 break;
1155
1156 case OP_CONST_HIGH16:
1157 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1158 loadConstantNoClobber(cUnit, rlResult.lowReg,
1159 mir->dalvikInsn.vB << 16);
1160 storeValue(cUnit, rlDest, rlResult);
1161 break;
1162
1163 case OP_CONST_WIDE_16:
1164 case OP_CONST_WIDE_32:
1165 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1166 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1167 //TUNING: do high separately to avoid load dependency
1168 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1169 storeValueWide(cUnit, rlDest, rlResult);
1170 break;
1171
1172 case OP_CONST_WIDE:
1173 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1174 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001175 mir->dalvikInsn.vB_wide & 0xffffffff,
1176 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001177 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001178 break;
1179
1180 case OP_CONST_WIDE_HIGH16:
1181 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1182 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1183 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001184 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001185 break;
1186
1187 case OP_MONITOR_ENTER:
1188 genMonitorEnter(cUnit, mir, rlSrc[0]);
1189 break;
1190
1191 case OP_MONITOR_EXIT:
1192 genMonitorExit(cUnit, mir, rlSrc[0]);
1193 break;
1194
1195 case OP_CHECK_CAST:
1196 genCheckCast(cUnit, mir, rlSrc[0]);
1197 break;
1198
1199 case OP_INSTANCE_OF:
1200 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1201 break;
1202
1203 case OP_NEW_INSTANCE:
1204 genNewInstance(cUnit, mir, rlDest);
1205 break;
1206
1207 case OP_THROW:
1208 genThrow(cUnit, mir, rlSrc[0]);
1209 break;
1210
1211 case OP_ARRAY_LENGTH:
1212 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001213 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001214 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee67bf8852011-08-17 17:51:35 -07001215 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg,
1216 mir->offset, NULL);
1217 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1218 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1219 rlResult.lowReg);
1220 storeValue(cUnit, rlDest, rlResult);
1221 break;
1222
1223 case OP_CONST_STRING:
1224 case OP_CONST_STRING_JUMBO:
1225 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1226 break;
1227
1228 case OP_CONST_CLASS:
1229 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1230 break;
1231
1232 case OP_FILL_ARRAY_DATA:
1233 genFillArrayData(cUnit, mir, rlSrc[0]);
1234 break;
1235
1236 case OP_FILLED_NEW_ARRAY:
1237 genFilledNewArray(cUnit, mir, false /* not range */);
1238 break;
1239
1240 case OP_FILLED_NEW_ARRAY_RANGE:
1241 genFilledNewArray(cUnit, mir, true /* range */);
1242 break;
1243
1244 case OP_NEW_ARRAY:
1245 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1246 break;
1247
1248 case OP_GOTO:
1249 case OP_GOTO_16:
1250 case OP_GOTO_32:
1251 // TUNING: add MIR flag to disable when unnecessary
1252 bool backwardBranch;
1253 backwardBranch = (bb->taken->startOffset <= mir->offset);
1254 if (backwardBranch) {
1255 genSuspendPoll(cUnit, mir);
1256 }
1257 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1258 break;
1259
1260 case OP_PACKED_SWITCH:
1261 genPackedSwitch(cUnit, mir, rlSrc[0]);
1262 break;
1263
1264 case OP_SPARSE_SWITCH:
1265 genSparseSwitch(cUnit, mir, rlSrc[0]);
1266 break;
1267
1268 case OP_CMPL_FLOAT:
1269 case OP_CMPG_FLOAT:
1270 case OP_CMPL_DOUBLE:
1271 case OP_CMPG_DOUBLE:
1272 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1273 break;
1274
1275 case OP_CMP_LONG:
1276 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1277 break;
1278
1279 case OP_IF_EQ:
1280 case OP_IF_NE:
1281 case OP_IF_LT:
1282 case OP_IF_GE:
1283 case OP_IF_GT:
1284 case OP_IF_LE: {
1285 bool backwardBranch;
1286 ArmConditionCode cond;
1287 backwardBranch = (bb->taken->startOffset <= mir->offset);
1288 if (backwardBranch) {
1289 genSuspendPoll(cUnit, mir);
1290 }
1291 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1292 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1293 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1294 switch(opcode) {
1295 case OP_IF_EQ:
1296 cond = kArmCondEq;
1297 break;
1298 case OP_IF_NE:
1299 cond = kArmCondNe;
1300 break;
1301 case OP_IF_LT:
1302 cond = kArmCondLt;
1303 break;
1304 case OP_IF_GE:
1305 cond = kArmCondGe;
1306 break;
1307 case OP_IF_GT:
1308 cond = kArmCondGt;
1309 break;
1310 case OP_IF_LE:
1311 cond = kArmCondLe;
1312 break;
1313 default:
1314 cond = (ArmConditionCode)0;
1315 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1316 }
1317 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1318 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1319 break;
1320 }
1321
1322 case OP_IF_EQZ:
1323 case OP_IF_NEZ:
1324 case OP_IF_LTZ:
1325 case OP_IF_GEZ:
1326 case OP_IF_GTZ:
1327 case OP_IF_LEZ: {
1328 bool backwardBranch;
1329 ArmConditionCode cond;
1330 backwardBranch = (bb->taken->startOffset <= mir->offset);
1331 if (backwardBranch) {
1332 genSuspendPoll(cUnit, mir);
1333 }
1334 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1335 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1336 switch(opcode) {
1337 case OP_IF_EQZ:
1338 cond = kArmCondEq;
1339 break;
1340 case OP_IF_NEZ:
1341 cond = kArmCondNe;
1342 break;
1343 case OP_IF_LTZ:
1344 cond = kArmCondLt;
1345 break;
1346 case OP_IF_GEZ:
1347 cond = kArmCondGe;
1348 break;
1349 case OP_IF_GTZ:
1350 cond = kArmCondGt;
1351 break;
1352 case OP_IF_LEZ:
1353 cond = kArmCondLe;
1354 break;
1355 default:
1356 cond = (ArmConditionCode)0;
1357 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1358 }
1359 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1360 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1361 break;
1362 }
1363
1364 case OP_AGET_WIDE:
1365 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1366 break;
1367 case OP_AGET:
1368 case OP_AGET_OBJECT:
1369 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1370 break;
1371 case OP_AGET_BOOLEAN:
1372 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1373 rlDest, 0);
1374 break;
1375 case OP_AGET_BYTE:
1376 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1377 break;
1378 case OP_AGET_CHAR:
1379 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1380 rlDest, 1);
1381 break;
1382 case OP_AGET_SHORT:
1383 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1384 break;
1385 case OP_APUT_WIDE:
1386 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1387 break;
1388 case OP_APUT:
1389 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1390 break;
1391 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001392 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001393 break;
1394 case OP_APUT_SHORT:
1395 case OP_APUT_CHAR:
1396 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1397 rlSrc[0], 1);
1398 break;
1399 case OP_APUT_BYTE:
1400 case OP_APUT_BOOLEAN:
1401 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1402 rlSrc[0], 0);
1403 break;
1404
1405 case OP_IGET_WIDE:
1406 case OP_IGET_WIDE_VOLATILE:
1407 genIGetWideX(cUnit, mir, rlDest, rlSrc[0]);
1408 break;
1409
1410 case OP_IGET:
1411 case OP_IGET_VOLATILE:
1412 case OP_IGET_OBJECT:
1413 case OP_IGET_OBJECT_VOLATILE:
1414 genIGetX(cUnit, mir, kWord, rlDest, rlSrc[0]);
1415 break;
1416
1417 case OP_IGET_BOOLEAN:
1418 case OP_IGET_BYTE:
1419 genIGetX(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
1420 break;
1421
1422 case OP_IGET_CHAR:
1423 genIGetX(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
1424 break;
1425
1426 case OP_IGET_SHORT:
1427 genIGetX(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
1428 break;
1429
1430 case OP_IPUT_WIDE:
1431 case OP_IPUT_WIDE_VOLATILE:
1432 genIPutWideX(cUnit, mir, rlSrc[0], rlSrc[1]);
1433 break;
1434
1435 case OP_IPUT_OBJECT:
1436 case OP_IPUT_OBJECT_VOLATILE:
1437 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
1438 break;
1439
1440 case OP_IPUT:
1441 case OP_IPUT_VOLATILE:
1442 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
1443 break;
1444
1445 case OP_IPUT_BOOLEAN:
1446 case OP_IPUT_BYTE:
1447 genIPutX(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
1448 break;
1449
1450 case OP_IPUT_CHAR:
1451 genIPutX(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
1452 break;
1453
1454 case OP_IPUT_SHORT:
1455 genIPutX(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
1456 break;
1457
1458 case OP_SGET:
1459 case OP_SGET_OBJECT:
1460 case OP_SGET_BOOLEAN:
1461 case OP_SGET_BYTE:
1462 case OP_SGET_CHAR:
1463 case OP_SGET_SHORT:
1464 genSget(cUnit, mir, rlResult, rlDest);
1465 break;
1466
1467 case OP_SGET_WIDE:
1468 genSgetWide(cUnit, mir, rlResult, rlDest);
1469 break;
1470
1471 case OP_SPUT:
1472 case OP_SPUT_OBJECT:
1473 case OP_SPUT_BOOLEAN:
1474 case OP_SPUT_BYTE:
1475 case OP_SPUT_CHAR:
1476 case OP_SPUT_SHORT:
1477 genSput(cUnit, mir, rlSrc[0]);
1478 break;
1479
1480 case OP_SPUT_WIDE:
1481 genSputWide(cUnit, mir, rlSrc[0]);
1482 break;
1483
1484 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001485 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1486 true /*range*/);
1487 break;
buzbee67bf8852011-08-17 17:51:35 -07001488 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001489 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1490 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001491 break;
1492
1493 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001494 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1495 false /*range*/);
1496 break;
buzbee67bf8852011-08-17 17:51:35 -07001497 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001498 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1499 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001500 break;
1501
1502 case OP_INVOKE_VIRTUAL:
1503 case OP_INVOKE_VIRTUAL_RANGE:
1504 genInvokeVirtual(cUnit, mir);
1505 break;
1506
1507 case OP_INVOKE_SUPER:
1508 case OP_INVOKE_SUPER_RANGE:
1509 genInvokeSuper(cUnit, mir);
1510 break;
1511
1512 case OP_INVOKE_INTERFACE:
1513 case OP_INVOKE_INTERFACE_RANGE:
1514 genInvokeInterface(cUnit, mir);
1515 break;
1516
1517 case OP_NEG_INT:
1518 case OP_NOT_INT:
1519 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1520 break;
1521
1522 case OP_NEG_LONG:
1523 case OP_NOT_LONG:
1524 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1525 break;
1526
1527 case OP_NEG_FLOAT:
1528 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1529 break;
1530
1531 case OP_NEG_DOUBLE:
1532 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1533 break;
1534
1535 case OP_INT_TO_LONG:
1536 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1537 if (rlSrc[0].location == kLocPhysReg) {
1538 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1539 } else {
1540 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1541 }
1542 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1543 rlResult.lowReg, 31);
1544 storeValueWide(cUnit, rlDest, rlResult);
1545 break;
1546
1547 case OP_LONG_TO_INT:
1548 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1549 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1550 storeValue(cUnit, rlDest, rlSrc[0]);
1551 break;
1552
1553 case OP_INT_TO_BYTE:
1554 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1555 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1556 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1557 storeValue(cUnit, rlDest, rlResult);
1558 break;
1559
1560 case OP_INT_TO_SHORT:
1561 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1562 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1563 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1564 storeValue(cUnit, rlDest, rlResult);
1565 break;
1566
1567 case OP_INT_TO_CHAR:
1568 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1569 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1570 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1571 storeValue(cUnit, rlDest, rlResult);
1572 break;
1573
1574 case OP_INT_TO_FLOAT:
1575 case OP_INT_TO_DOUBLE:
1576 case OP_LONG_TO_FLOAT:
1577 case OP_LONG_TO_DOUBLE:
1578 case OP_FLOAT_TO_INT:
1579 case OP_FLOAT_TO_LONG:
1580 case OP_FLOAT_TO_DOUBLE:
1581 case OP_DOUBLE_TO_INT:
1582 case OP_DOUBLE_TO_LONG:
1583 case OP_DOUBLE_TO_FLOAT:
1584 genConversion(cUnit, mir);
1585 break;
1586
1587 case OP_ADD_INT:
1588 case OP_SUB_INT:
1589 case OP_MUL_INT:
1590 case OP_DIV_INT:
1591 case OP_REM_INT:
1592 case OP_AND_INT:
1593 case OP_OR_INT:
1594 case OP_XOR_INT:
1595 case OP_SHL_INT:
1596 case OP_SHR_INT:
1597 case OP_USHR_INT:
1598 case OP_ADD_INT_2ADDR:
1599 case OP_SUB_INT_2ADDR:
1600 case OP_MUL_INT_2ADDR:
1601 case OP_DIV_INT_2ADDR:
1602 case OP_REM_INT_2ADDR:
1603 case OP_AND_INT_2ADDR:
1604 case OP_OR_INT_2ADDR:
1605 case OP_XOR_INT_2ADDR:
1606 case OP_SHL_INT_2ADDR:
1607 case OP_SHR_INT_2ADDR:
1608 case OP_USHR_INT_2ADDR:
1609 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1610 break;
1611
1612 case OP_ADD_LONG:
1613 case OP_SUB_LONG:
1614 case OP_MUL_LONG:
1615 case OP_DIV_LONG:
1616 case OP_REM_LONG:
1617 case OP_AND_LONG:
1618 case OP_OR_LONG:
1619 case OP_XOR_LONG:
1620 case OP_ADD_LONG_2ADDR:
1621 case OP_SUB_LONG_2ADDR:
1622 case OP_MUL_LONG_2ADDR:
1623 case OP_DIV_LONG_2ADDR:
1624 case OP_REM_LONG_2ADDR:
1625 case OP_AND_LONG_2ADDR:
1626 case OP_OR_LONG_2ADDR:
1627 case OP_XOR_LONG_2ADDR:
1628 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1629 break;
1630
buzbee67bf8852011-08-17 17:51:35 -07001631 case OP_SHL_LONG:
1632 case OP_SHR_LONG:
1633 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001634 case OP_SHL_LONG_2ADDR:
1635 case OP_SHR_LONG_2ADDR:
1636 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001637 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1638 break;
1639
1640 case OP_ADD_FLOAT:
1641 case OP_SUB_FLOAT:
1642 case OP_MUL_FLOAT:
1643 case OP_DIV_FLOAT:
1644 case OP_REM_FLOAT:
1645 case OP_ADD_FLOAT_2ADDR:
1646 case OP_SUB_FLOAT_2ADDR:
1647 case OP_MUL_FLOAT_2ADDR:
1648 case OP_DIV_FLOAT_2ADDR:
1649 case OP_REM_FLOAT_2ADDR:
1650 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1651 break;
1652
1653 case OP_ADD_DOUBLE:
1654 case OP_SUB_DOUBLE:
1655 case OP_MUL_DOUBLE:
1656 case OP_DIV_DOUBLE:
1657 case OP_REM_DOUBLE:
1658 case OP_ADD_DOUBLE_2ADDR:
1659 case OP_SUB_DOUBLE_2ADDR:
1660 case OP_MUL_DOUBLE_2ADDR:
1661 case OP_DIV_DOUBLE_2ADDR:
1662 case OP_REM_DOUBLE_2ADDR:
1663 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1664 break;
1665
1666 case OP_RSUB_INT:
1667 case OP_ADD_INT_LIT16:
1668 case OP_MUL_INT_LIT16:
1669 case OP_DIV_INT_LIT16:
1670 case OP_REM_INT_LIT16:
1671 case OP_AND_INT_LIT16:
1672 case OP_OR_INT_LIT16:
1673 case OP_XOR_INT_LIT16:
1674 case OP_ADD_INT_LIT8:
1675 case OP_RSUB_INT_LIT8:
1676 case OP_MUL_INT_LIT8:
1677 case OP_DIV_INT_LIT8:
1678 case OP_REM_INT_LIT8:
1679 case OP_AND_INT_LIT8:
1680 case OP_OR_INT_LIT8:
1681 case OP_XOR_INT_LIT8:
1682 case OP_SHL_INT_LIT8:
1683 case OP_SHR_INT_LIT8:
1684 case OP_USHR_INT_LIT8:
1685 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1686 break;
1687
1688 default:
1689 res = true;
1690 }
1691 return res;
1692}
1693
1694static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1695 "kMirOpPhi",
1696 "kMirOpNullNRangeUpCheck",
1697 "kMirOpNullNRangeDownCheck",
1698 "kMirOpLowerBound",
1699 "kMirOpPunt",
1700 "kMirOpCheckInlinePrediction",
1701};
1702
1703/* Extended MIR instructions like PHI */
1704static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1705{
1706 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1707 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1708 strcpy(msg, extendedMIROpNames[opOffset]);
1709 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1710
1711 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1712 case kMirOpPhi: {
1713 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1714 op->flags.isNop = true;
1715 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1716 break;
1717 }
1718 default:
1719 break;
1720 }
1721}
1722
1723/* If there are any ins passed in registers that have not been promoted
1724 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001725 * Note: at this pointCopy any ins that are passed in register to their
1726 * home location */
buzbee67bf8852011-08-17 17:51:35 -07001727static void flushIns(CompilationUnit* cUnit)
1728{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001729 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001730 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001731 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1732 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001733 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001734 int startLoc = cUnit->method->NumRegisters() -
1735 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001736 for (int i = 0; i < inRegs; i++) {
1737 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001738 //TUNING: be smarter about flushing ins to frame
1739 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001740 if (loc.location == kLocPhysReg) {
1741 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001742 }
1743 }
1744
1745 // Handle special case of wide argument half in regs, half in frame
1746 if (inRegs == 3) {
1747 RegLocation loc = cUnit->regLocation[startLoc + 2];
1748 if (loc.wide && loc.location == kLocPhysReg) {
1749 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001750 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001751 inRegs++;
1752 }
1753 }
1754
1755 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001756 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001757 RegLocation loc = cUnit->regLocation[startLoc + i];
1758 if (loc.fpLocation == kLocPhysReg) {
1759 loc.location = kLocPhysReg;
1760 loc.fp = true;
1761 loc.lowReg = loc.fpLowReg;
1762 loc.highReg = loc.fpHighReg;
1763 }
1764 if (loc.location == kLocPhysReg) {
1765 if (loc.wide) {
1766 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1767 loc.lowReg, loc.highReg, INVALID_SREG);
1768 i++;
1769 } else {
buzbee561227c2011-09-02 15:28:19 -07001770 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001771 }
1772 }
1773 i++;
1774 }
1775}
1776
1777/* Handle the content in each basic block */
1778static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1779{
1780 MIR* mir;
1781 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1782 int blockId = bb->id;
1783
1784 cUnit->curBlock = bb;
1785 labelList[blockId].operands[0] = bb->startOffset;
1786
1787 /* Insert the block label */
1788 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1789 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1790
1791 oatClobberAllRegs(cUnit);
1792 oatResetNullCheck(cUnit);
1793
1794 ArmLIR* headLIR = NULL;
1795
1796 if (bb->blockType == kEntryBlock) {
1797 /*
1798 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1799 * mechanism know so it doesn't try to use any of them when
1800 * expanding the frame or flushing. This leaves the utility
1801 * code with a single temp: r12. This should be enough.
1802 */
1803 oatLockTemp(cUnit, r0);
1804 oatLockTemp(cUnit, r1);
1805 oatLockTemp(cUnit, r2);
1806 oatLockTemp(cUnit, r3);
1807 newLIR0(cUnit, kArmPseudoMethodEntry);
1808 /* Spill core callee saves */
1809 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1810 /* Need to spill any FP regs? */
1811 if (cUnit->numFPSpills) {
1812 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1813 }
1814 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1815 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1816 flushIns(cUnit);
1817 oatFreeTemp(cUnit, r0);
1818 oatFreeTemp(cUnit, r1);
1819 oatFreeTemp(cUnit, r2);
1820 oatFreeTemp(cUnit, r3);
1821 } else if (bb->blockType == kExitBlock) {
1822 newLIR0(cUnit, kArmPseudoMethodExit);
1823 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1824 /* Need to restore any FP callee saves? */
1825 if (cUnit->numFPSpills) {
1826 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1827 }
1828 if (cUnit->coreSpillMask & (1 << rLR)) {
1829 /* Unspill rLR to rPC */
1830 cUnit->coreSpillMask &= ~(1 << rLR);
1831 cUnit->coreSpillMask |= (1 << rPC);
1832 }
1833 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1834 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1835 /* We didn't pop to rPC, so must do a bv rLR */
1836 newLIR1(cUnit, kThumbBx, rLR);
1837 }
1838 }
1839
1840 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1841
1842 oatResetRegPool(cUnit);
1843 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1844 oatClobberAllRegs(cUnit);
1845 }
1846
1847 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1848 oatResetDefTracking(cUnit);
1849 }
1850
1851 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1852 handleExtendedMethodMIR(cUnit, mir);
1853 continue;
1854 }
1855
1856 cUnit->currentDalvikOffset = mir->offset;
1857
1858 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1859 InstructionFormat dalvikFormat =
1860 dexGetFormatFromOpcode(dalvikOpcode);
1861
1862 ArmLIR* boundaryLIR;
1863
1864 /* Mark the beginning of a Dalvik instruction for line tracking */
1865 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1866 (int) oatGetDalvikDisassembly(
1867 &mir->dalvikInsn, ""));
1868 /* Remember the first LIR for this block */
1869 if (headLIR == NULL) {
1870 headLIR = boundaryLIR;
1871 /* Set the first boundaryLIR as a scheduling barrier */
1872 headLIR->defMask = ENCODE_ALL;
1873 }
1874
1875 /* Don't generate the SSA annotation unless verbose mode is on */
1876 if (cUnit->printMe && mir->ssaRep) {
1877 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1878 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1879 }
1880
1881 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1882
1883 if (notHandled) {
1884 char buf[100];
1885 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1886 mir->offset,
1887 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1888 dalvikFormat);
1889 LOG(FATAL) << buf;
1890 }
1891 }
1892
1893 if (headLIR) {
1894 /*
1895 * Eliminate redundant loads/stores and delay stores into later
1896 * slots
1897 */
1898 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1899 cUnit->lastLIRInsn);
1900
1901 /*
1902 * Generate an unconditional branch to the fallthrough block.
1903 */
1904 if (bb->fallThrough) {
1905 genUnconditionalBranch(cUnit,
1906 &labelList[bb->fallThrough->id]);
1907 }
1908 }
1909 return false;
1910}
1911
1912/*
1913 * Nop any unconditional branches that go to the next instruction.
1914 * Note: new redundant branches may be inserted later, and we'll
1915 * use a check in final instruction assembly to nop those out.
1916 */
1917void removeRedundantBranches(CompilationUnit* cUnit)
1918{
1919 ArmLIR* thisLIR;
1920
1921 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1922 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1923 thisLIR = NEXT_LIR(thisLIR)) {
1924
1925 /* Branch to the next instruction */
1926 if ((thisLIR->opcode == kThumbBUncond) ||
1927 (thisLIR->opcode == kThumb2BUncond)) {
1928 ArmLIR* nextLIR = thisLIR;
1929
1930 while (true) {
1931 nextLIR = NEXT_LIR(nextLIR);
1932
1933 /*
1934 * Is the branch target the next instruction?
1935 */
1936 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1937 thisLIR->flags.isNop = true;
1938 break;
1939 }
1940
1941 /*
1942 * Found real useful stuff between the branch and the target.
1943 * Need to explicitly check the lastLIRInsn here because it
1944 * might be the last real instruction.
1945 */
1946 if (!isPseudoOpcode(nextLIR->opcode) ||
1947 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1948 break;
1949 }
1950 }
1951 }
1952}
1953
1954void oatMethodMIR2LIR(CompilationUnit* cUnit)
1955{
1956 /* Used to hold the labels of each block */
1957 cUnit->blockLabelList =
1958 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
1959
1960 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
1961 kPreOrderDFSTraversal, false /* Iterative */);
1962 removeRedundantBranches(cUnit);
1963}
1964
1965/* Common initialization routine for an architecture family */
1966bool oatArchInit()
1967{
1968 int i;
1969
1970 for (i = 0; i < kArmLast; i++) {
1971 if (EncodingMap[i].opcode != i) {
1972 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
1973 " is wrong: expecting " << i << ", seeing " <<
1974 (int)EncodingMap[i].opcode;
1975 }
1976 }
1977
1978 return oatArchVariantInit();
1979}
1980
1981/* Needed by the Assembler */
1982void oatSetupResourceMasks(ArmLIR* lir)
1983{
1984 setupResourceMasks(lir);
1985}
1986
1987/* Needed by the ld/st optmizatons */
1988ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
1989{
1990 return genRegCopyNoInsert(cUnit, rDest, rSrc);
1991}
1992
1993/* Needed by the register allocator */
1994ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
1995{
1996 return genRegCopy(cUnit, rDest, rSrc);
1997}
1998
1999/* Needed by the register allocator */
2000void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2001 int srcLo, int srcHi)
2002{
2003 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2004}
2005
2006void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2007 int displacement, int rSrc, OpSize size)
2008{
2009 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2010}
2011
2012void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2013 int displacement, int rSrcLo, int rSrcHi)
2014{
2015 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2016}