blob: 9c87659be8220c36416fb5eb0df39c9ffcfe68b0 [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
buzbeee9a72f62011-09-04 17:59:07 -070018
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
40 opReg(cUnit, kOpBlx, rLR);
41 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
70 opReg(cUnit, kOpBlx, 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
148 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
149 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700150 oatFlushAllRegs(cUnit);
151 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
152 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
153 loadCurrMethodDirect(cUnit, r1);
154 loadValueDirect(cUnit, rlSrc, r2);
155 opReg(cUnit, kOpBlx, rLR);
156 oatClobberCallRegs(cUnit);
157 } else {
buzbee1da522d2011-09-04 11:22:20 -0700158 // fast path
159 int fieldOffset = field->GetOffset().Int32Value();
160 art::ClassLinker* class_linker = art::Runtime::Current()->
161 GetClassLinker();
162 const art::DexFile& dex_file = class_linker->
163 FindDexFile(field->GetDeclaringClass()->GetDexCache());
164 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
165 int typeIdx = field_id.class_idx_;
166 // Using fixed register to sync with slow path
167 int rMethod = r1;
168 oatLockTemp(cUnit, rMethod);
169 loadCurrMethodDirect(cUnit, rMethod);
170 int rBase = r0;
171 oatLockTemp(cUnit, rBase);
172 loadWordDisp(cUnit, rMethod,
173 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
174 rBase);
175 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
176 sizeof(int32_t*)* typeIdx, rBase);
177 // TUNING: fast path should fall through
178 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
179 loadWordDisp(cUnit, rSELF,
180 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
181 loadConstant(cUnit, r0, typeIdx);
182 opReg(cUnit, kOpBlx, rLR);
183 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
184 skipTarget->defMask = ENCODE_ALL;
185 branchOver->generic.target = (LIR*)skipTarget;
186 rlSrc = oatGetSrc(cUnit, mir, 0);
187 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
188 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700189#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700190 if (field->IsVolatile()) {
191 oatGenMemBarrier(cUnit, kSY);
192 }
buzbee67bf8852011-08-17 17:51:35 -0700193#endif
buzbee1da522d2011-09-04 11:22:20 -0700194 if (isObject) {
195 markGCCard(cUnit, rlSrc.lowReg, rBase);
196 }
197 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700198 }
buzbee67bf8852011-08-17 17:51:35 -0700199}
200
201static void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
202{
buzbee1da522d2011-09-04 11:22:20 -0700203 int fieldIdx = mir->dalvikInsn.vB;
204 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee9a72f62011-09-04 17:59:07 -0700205 if (FORCE_SLOW || field == NULL) {
buzbeee1931742011-08-28 21:15:53 -0700206 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700207 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700208 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
209 loadCurrMethodDirect(cUnit, r1);
210 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
211 opReg(cUnit, kOpBlx, rLR);
212 oatClobberCallRegs(cUnit);
213 } else {
buzbee1da522d2011-09-04 11:22:20 -0700214 // fast path
215 int fieldOffset = field->GetOffset().Int32Value();
216 art::ClassLinker* class_linker = art::Runtime::Current()->
217 GetClassLinker();
218 const art::DexFile& dex_file = class_linker->
219 FindDexFile(field->GetDeclaringClass()->GetDexCache());
220 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
221 int typeIdx = field_id.class_idx_;
222 // Using fixed register to sync with slow path
223 int rMethod = r1;
224 oatLockTemp(cUnit, rMethod);
225 loadCurrMethodDirect(cUnit, r1);
226 int rBase = r0;
227 oatLockTemp(cUnit, rBase);
228 loadWordDisp(cUnit, rMethod,
229 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
230 rBase);
231 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
232 sizeof(int32_t*)* typeIdx, rBase);
233 // TUNING: fast path should fall through
234 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
235 loadWordDisp(cUnit, rSELF,
236 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
237 loadConstant(cUnit, r0, typeIdx);
238 opReg(cUnit, kOpBlx, rLR);
239 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
240 skipTarget->defMask = ENCODE_ALL;
241 branchOver->generic.target = (LIR*)skipTarget;
242 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
243 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
244 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
245 rlSrc.highReg);
246#if ANDROID_SMP != 0
247 if (field->IsVolatile()) {
248 oatGenMemBarrier(cUnit, kSY);
249 }
buzbeec143c552011-08-20 17:38:58 -0700250#endif
buzbee1da522d2011-09-04 11:22:20 -0700251 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700252 }
buzbee67bf8852011-08-17 17:51:35 -0700253}
254
255
buzbee67bf8852011-08-17 17:51:35 -0700256static void genSgetWide(CompilationUnit* cUnit, MIR* mir,
257 RegLocation rlResult, RegLocation rlDest)
258{
buzbee1da522d2011-09-04 11:22:20 -0700259 int fieldIdx = mir->dalvikInsn.vB;
260 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee9a72f62011-09-04 17:59:07 -0700261 if (FORCE_SLOW || field == NULL) {
buzbeee1931742011-08-28 21:15:53 -0700262 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700263 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700264 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
265 loadCurrMethodDirect(cUnit, r1);
266 opReg(cUnit, kOpBlx, rLR);
267 RegLocation rlResult = oatGetReturnWide(cUnit);
268 storeValueWide(cUnit, rlDest, rlResult);
269 } else {
buzbee1da522d2011-09-04 11:22:20 -0700270 // Fast path
271 int fieldOffset = field->GetOffset().Int32Value();
272 art::ClassLinker* class_linker = art::Runtime::Current()->
273 GetClassLinker();
274 const art::DexFile& dex_file = class_linker->
275 FindDexFile(field->GetDeclaringClass()->GetDexCache());
276 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
277 int typeIdx = field_id.class_idx_;
278 // Using fixed register to sync with slow path
279 int rMethod = r1;
280 oatLockTemp(cUnit, rMethod);
281 loadCurrMethodDirect(cUnit, rMethod);
282 int rBase = r0;
283 oatLockTemp(cUnit, rBase);
284 loadWordDisp(cUnit, rMethod,
285 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
286 rBase);
287 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
288 sizeof(int32_t*)* typeIdx, rBase);
289 // TUNING: fast path should fall through
290 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
291 loadWordDisp(cUnit, rSELF,
292 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
293 loadConstant(cUnit, r0, typeIdx);
294 opReg(cUnit, kOpBlx, rLR);
295 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
296 skipTarget->defMask = ENCODE_ALL;
297 branchOver->generic.target = (LIR*)skipTarget;
298 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
299 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
300#if ANDROID_SMP != 0
301 if (isVolatile) {
302 oatGenMemBarrier(cUnit, kSY);
303 }
buzbeec143c552011-08-20 17:38:58 -0700304#endif
buzbee1da522d2011-09-04 11:22:20 -0700305 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
306 rlResult.highReg, INVALID_SREG);
307 oatFreeTemp(cUnit, rBase);
308 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700309 }
buzbee67bf8852011-08-17 17:51:35 -0700310}
311
312static void genSget(CompilationUnit* cUnit, MIR* mir,
313 RegLocation rlResult, RegLocation rlDest)
314{
buzbee1da522d2011-09-04 11:22:20 -0700315 int fieldIdx = mir->dalvikInsn.vB;
316 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee1931742011-08-28 21:15:53 -0700317 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
318 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbeee9a72f62011-09-04 17:59:07 -0700319 if (FORCE_SLOW || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700320 // Slow path
321 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
322 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700323 oatFlushAllRegs(cUnit);
324 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
325 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
326 loadCurrMethodDirect(cUnit, r1);
327 opReg(cUnit, kOpBlx, rLR);
328 RegLocation rlResult = oatGetReturn(cUnit);
329 storeValue(cUnit, rlDest, rlResult);
330 } else {
buzbee1da522d2011-09-04 11:22:20 -0700331 // Fast path
332 int fieldOffset = field->GetOffset().Int32Value();
333 art::ClassLinker* class_linker = art::Runtime::Current()->
334 GetClassLinker();
335 const art::DexFile& dex_file = class_linker->
336 FindDexFile(field->GetDeclaringClass()->GetDexCache());
337 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
338 int typeIdx = field_id.class_idx_;
339 // Using fixed register to sync with slow path
340 int rMethod = r1;
341 oatLockTemp(cUnit, rMethod);
342 loadCurrMethodDirect(cUnit, rMethod);
343 int rBase = r0;
344 oatLockTemp(cUnit, rBase);
345 loadWordDisp(cUnit, rMethod,
346 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
347 rBase);
348 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
349 sizeof(int32_t*)* typeIdx, rBase);
350 // TUNING: fast path should fall through
351 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
352 loadWordDisp(cUnit, rSELF,
353 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
354 loadConstant(cUnit, r0, typeIdx);
355 opReg(cUnit, kOpBlx, rLR);
356 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
357 skipTarget->defMask = ENCODE_ALL;
358 branchOver->generic.target = (LIR*)skipTarget;
359 rlDest = oatGetDest(cUnit, mir, 0);
360 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700361#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700362 if (isVolatile) {
363 oatGenMemBarrier(cUnit, kSY);
364 }
buzbee67bf8852011-08-17 17:51:35 -0700365#endif
buzbee1da522d2011-09-04 11:22:20 -0700366 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
367 oatFreeTemp(cUnit, rBase);
368 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700369 }
buzbee67bf8852011-08-17 17:51:35 -0700370}
371
buzbee561227c2011-09-02 15:28:19 -0700372typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
373 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700374
375/*
376 * Bit of a hack here - in leiu of a real scheduling pass,
377 * emit the next instruction in static & direct invoke sequences.
378 */
379static int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700380 DecodedInstruction* dInsn, int state,
381 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700382{
buzbee561227c2011-09-02 15:28:19 -0700383 DCHECK(rollback == NULL);
384 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700385 switch(state) {
386 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700387 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700388 break;
buzbee561227c2011-09-02 15:28:19 -0700389 case 1: // Get method->code_and_direct_methods_
390 loadWordDisp(cUnit, r0,
391 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
392 r0);
buzbee67bf8852011-08-17 17:51:35 -0700393 break;
buzbee561227c2011-09-02 15:28:19 -0700394 case 2: // Grab target method* and target code_
395 loadWordDisp(cUnit, r0,
396 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
397 loadWordDisp(cUnit, r0,
398 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700399 break;
400 default:
401 return -1;
402 }
403 return state + 1;
404}
405
buzbee67bf8852011-08-17 17:51:35 -0700406/*
407 * Bit of a hack here - in leiu of a real scheduling pass,
408 * emit the next instruction in a virtual invoke sequence.
409 * We can use rLR as a temp prior to target address loading
410 * Note also that we'll load the first argument ("this") into
411 * r1 here rather than the standard loadArgRegs.
412 */
413static int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700414 DecodedInstruction* dInsn, int state,
415 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700416{
buzbee561227c2011-09-02 15:28:19 -0700417 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700418 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700419 /*
420 * This is the fast path in which the target virtual method is
421 * fully resolved at compile time.
422 */
423 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
424 Get(dInsn->vB);
425 CHECK(baseMethod != NULL);
426 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700427 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700428 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700429 rlArg = oatGetSrc(cUnit, mir, 0);
430 loadValueDirectFixed(cUnit, rlArg, r1);
431 break;
buzbee561227c2011-09-02 15:28:19 -0700432 case 1: // Is "this" null? [use r1]
433 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
434 // get this->klass_ [use r1, set rLR]
435 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700436 break;
buzbee561227c2011-09-02 15:28:19 -0700437 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
438 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700439 break;
buzbee561227c2011-09-02 15:28:19 -0700440 case 3: // Get target method [use rLR, set r0]
441 loadWordDisp(cUnit, rLR, (target_idx * 4) +
442 art::Array::DataOffset().Int32Value(), r0);
443 break;
444 case 4: // Get the target compiled code address [uses r0, sets rLR]
445 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700446 break;
447 default:
448 return -1;
449 }
450 return state + 1;
451}
452
buzbee7b1b86d2011-08-26 18:59:10 -0700453static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700454 DecodedInstruction* dInsn, int state,
455 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700456{
buzbee561227c2011-09-02 15:28:19 -0700457 DCHECK(rollback != NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700458 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700459 ArmLIR* skipBranch;
460 ArmLIR* skipTarget;
461 /*
462 * This handles the case in which the base method is not fully
463 * resolved at compile time. We must generate code to test
464 * for resolution a run time, bail to the slow path if not to
465 * fill in all the tables. In the latter case, we'll restart at
466 * at the beginning of the sequence.
467 */
buzbee7b1b86d2011-08-26 18:59:10 -0700468 switch(state) {
469 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700470 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700471 break;
buzbee561227c2011-09-02 15:28:19 -0700472 case 1: // Get method->dex_cache_resolved_methods_
473 loadWordDisp(cUnit, r0,
474 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700475 break;
buzbee561227c2011-09-02 15:28:19 -0700476 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
477 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
478 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700479 break;
buzbee561227c2011-09-02 15:28:19 -0700480 case 3: // Resolved?
481 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
482 // Slowest path, bail to helper, rollback and retry
483 loadWordDisp(cUnit, rSELF,
484 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
485 loadConstant(cUnit, r1, dInsn->vB);
486 newLIR1(cUnit, kThumbBlxR, rLR);
487 genUnconditionalBranch(cUnit, rollback);
488 // Resume normal slow path
489 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
490 skipTarget->defMask = ENCODE_ALL;
491 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700492 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700493 loadBaseDisp(cUnit, mir, rLR,
494 Method::GetMethodIndexOffset().Int32Value(), r0,
495 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700496 // Load "this" [set r1]
497 rlArg = oatGetSrc(cUnit, mir, 0);
498 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700499 break;
500 case 4:
501 // Is "this" null? [use r1]
502 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
503 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700504 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700505 break;
buzbee561227c2011-09-02 15:28:19 -0700506 case 5:
507 // get this->klass_->vtable_ [usr rLR, set rLR]
508 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
509 DCHECK((art::Array::DataOffset().Int32Value() & 0x3) == 0);
510 // In load shadow fold vtable_ object header size into method_index_
511 opRegImm(cUnit, kOpAdd, r0,
512 art::Array::DataOffset().Int32Value() / 4);
513 // Get target Method*
514 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
515 break;
516 case 6: // Get the target compiled code address [uses r0, sets rLR]
517 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700518 break;
519 default:
520 return -1;
521 }
522 return state + 1;
523}
524
buzbee67bf8852011-08-17 17:51:35 -0700525/* Load up to 3 arguments in r1..r3 */
526static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
527 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700528 int *args, NextCallInsn nextCallInsn, ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700529{
530 for (int i = 0; i < 3; i++) {
531 if (args[i] != INVALID_REG) {
buzbee1b4c8592011-08-31 10:43:51 -0700532 // Arguments are treated as a series of untyped 32-bit values.
buzbeee9a72f62011-09-04 17:59:07 -0700533 RegLocation rlArg = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700534 rlArg.wide = false;
buzbee67bf8852011-08-17 17:51:35 -0700535 loadValueDirectFixed(cUnit, rlArg, r1 + i);
buzbee561227c2011-09-02 15:28:19 -0700536 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700537 }
538 }
539 return callState;
540}
541
buzbee4a3164f2011-09-03 11:25:10 -0700542// Interleave launch code for INVOKE_INTERFACE.
buzbee67bf8852011-08-17 17:51:35 -0700543static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700544 DecodedInstruction* dInsn, int state,
545 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700546{
buzbee67bf8852011-08-17 17:51:35 -0700547 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700548 case 0: // Load trampoline target
549 loadWordDisp(cUnit, rSELF,
550 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
551 rLR);
552 // Load r0 with method index
553 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700554 break;
buzbee67bf8852011-08-17 17:51:35 -0700555 default:
556 return -1;
557 }
558 return state + 1;
559}
560
buzbee67bf8852011-08-17 17:51:35 -0700561/*
562 * Interleave launch code for INVOKE_SUPER. See comments
563 * for nextVCallIns.
564 */
565static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700566 DecodedInstruction* dInsn, int state,
567 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700568{
buzbee4a3164f2011-09-03 11:25:10 -0700569 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700570 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700571 /*
572 * This is the fast path in which the target virtual method is
573 * fully resolved at compile time. Note also that this path assumes
574 * that the check to verify that the target method index falls
575 * within the size of the super's vtable has been done at compile-time.
576 */
577 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
578 Get(dInsn->vB);
579 CHECK(baseMethod != NULL);
580 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
581 CHECK(superClass != NULL);
582 int32_t target_idx = baseMethod->GetMethodIndex();
583 CHECK(superClass->GetVTable()->GetLength() > target_idx);
584 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
585 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700586 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700587 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700588 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700589 // Load "this" [set r1]
590 rlArg = oatGetSrc(cUnit, mir, 0);
591 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700592 // Get method->declaring_class_ [use r0, set rLR]
593 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
594 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700595 // Is "this" null? [use r1]
596 genNullCheck(cUnit, oatSSASrc(mir,0), r1,
597 mir->offset, NULL);
buzbee4a3164f2011-09-03 11:25:10 -0700598 break;
599 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
600 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
601 rLR);
602 break;
603 case 2: // Get ...->super_class_->vtable [u/s rLR]
604 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
605 break;
606 case 3: // Get target method [use rLR, set r0]
607 loadWordDisp(cUnit, rLR, (target_idx * 4) +
608 art::Array::DataOffset().Int32Value(), r0);
609 break;
610 case 4: // Get the target compiled code address [uses r0, sets rLR]
611 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
612 break;
buzbee67bf8852011-08-17 17:51:35 -0700613 default:
614 return -1;
615 }
buzbee4a3164f2011-09-03 11:25:10 -0700616 return state + 1;
617}
618
619/* Slow-path version of nextSuperCallInsn */
620static int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
621 DecodedInstruction* dInsn, int state,
622 ArmLIR* rollback)
623{
624 DCHECK(rollback != NULL);
625 RegLocation rlArg;
626 ArmLIR* skipBranch;
627 ArmLIR* skipTarget;
628 int tReg;
629 /*
630 * This handles the case in which the base method is not fully
631 * resolved at compile time. We must generate code to test
632 * for resolution a run time, bail to the slow path if not to
633 * fill in all the tables. In the latter case, we'll restart at
634 * at the beginning of the sequence.
635 */
636 switch(state) {
637 case 0: // Get the current Method* [sets r0]
638 loadCurrMethodDirect(cUnit, r0);
639 break;
640 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
641 loadWordDisp(cUnit, r0,
642 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
643 break;
644 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
645 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
646 art::Array::DataOffset().Int32Value(), rLR);
647 break;
648 case 3: // Resolved?
649 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
650 // Slowest path, bail to helper, rollback and retry
651 loadWordDisp(cUnit, rSELF,
652 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
653 loadConstant(cUnit, r1, dInsn->vB);
654 newLIR1(cUnit, kThumbBlxR, rLR);
655 genUnconditionalBranch(cUnit, rollback);
656 // Resume normal slow path
657 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
658 skipTarget->defMask = ENCODE_ALL;
659 skipBranch->generic.target = (LIR*)skipTarget;
660 // Get base_method->method_index [usr rLR, set rLR]
661 loadBaseDisp(cUnit, mir, rLR,
662 Method::GetMethodIndexOffset().Int32Value(), rLR,
663 kUnsignedHalf, INVALID_SREG);
664 // Load "this" [set r1]
665 rlArg = oatGetSrc(cUnit, mir, 0);
666 loadValueDirectFixed(cUnit, rlArg, r1);
667 // Load curMethod->declaring_class_ [uses r0, sets r0]
668 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
669 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700670 // Null this?
671 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
672 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700673 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
674 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700675 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700676 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee4a3164f2011-09-03 11:25:10 -0700677 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
678 // Range check, throw NSM on failure
679 tReg = oatAllocTemp(cUnit);
680 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
681 tReg);
682 genBoundsCheck(cUnit, tReg, rLR, mir->offset, NULL);
683 oatFreeTemp(cUnit, tReg);
684 }
buzbee6a0f7f52011-09-05 16:14:20 -0700685 // Adjust vtable_ base past object header
686 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700687 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700688 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700689 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700690 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700691 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
692 break;
693 default:
694 return -1;
695 }
buzbee67bf8852011-08-17 17:51:35 -0700696 return state + 1;
697}
698
699/*
700 * Load up to 5 arguments, the first three of which will be in
701 * r1 .. r3. On entry r0 contains the current method pointer,
702 * and as part of the load sequence, it must be replaced with
703 * the target method pointer. Note, this may also be called
704 * for "range" variants if the number of arguments is 5 or fewer.
705 */
706static int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
707 DecodedInstruction* dInsn, int callState,
708 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700709 NextCallInsn nextCallInsn, ArmLIR* rollback,
710 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700711{
712 RegLocation rlArg;
713 int registerArgs[3];
714
715 /* If no arguments, just return */
716 if (dInsn->vA == 0)
717 return callState;
718
buzbee561227c2011-09-02 15:28:19 -0700719 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700720
721 /*
722 * Load frame arguments arg4 & arg5 first. Coded a little odd to
723 * pre-schedule the method pointer target.
724 */
725 for (unsigned int i=3; i < dInsn->vA; i++) {
726 int reg;
buzbeee9a72f62011-09-04 17:59:07 -0700727 rlArg = oatUpdateLoc(cUnit, oatGetSrc(cUnit, mir, i));
buzbee67bf8852011-08-17 17:51:35 -0700728 if (rlArg.location == kLocPhysReg) {
729 reg = rlArg.lowReg;
730 } else {
buzbee109bd6a2011-09-06 13:58:41 -0700731 // r3 is the last arg register loaded, so can safely be used here
732 reg = r3;
733 loadValueDirectFixed(cUnit, rlArg, reg);
buzbee561227c2011-09-02 15:28:19 -0700734 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700735 }
736 storeBaseDisp(cUnit, rSP, (i + 1) * 4, reg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700737 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700738 }
739
740 /* Load register arguments r1..r3 */
buzbeee9a72f62011-09-04 17:59:07 -0700741 for (unsigned int i = 0; i < 3; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700742 if (i < dInsn->vA)
743 registerArgs[i] = (isRange) ? dInsn->vC + i : i;
744 else
745 registerArgs[i] = INVALID_REG;
746 }
buzbeee9a72f62011-09-04 17:59:07 -0700747 if (skipThis) {
748 registerArgs[0] = INVALID_REG;
749 }
buzbee67bf8852011-08-17 17:51:35 -0700750 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
buzbee561227c2011-09-02 15:28:19 -0700751 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700752
buzbee6a0f7f52011-09-05 16:14:20 -0700753 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700754 // Load direct & need a "this" null check?
755 if (pcrLabel) {
756 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1,
757 mir->offset, NULL);
758 }
759 return callState;
760}
761
762/*
763 * May have 0+ arguments (also used for jumbo). Note that
764 * source virtual registers may be in physical registers, so may
765 * need to be flushed to home location before copying. This
766 * applies to arg3 and above (see below).
767 *
768 * Two general strategies:
769 * If < 20 arguments
770 * Pass args 3-18 using vldm/vstm block copy
771 * Pass arg0, arg1 & arg2 in r1-r3
772 * If 20+ arguments
773 * Pass args arg19+ using memcpy block copy
774 * Pass arg0, arg1 & arg2 in r1-r3
775 *
776 */
777static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
778 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700779 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700780 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700781{
782 int firstArg = dInsn->vC;
783 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700784 int registerArgs[3];
785
buzbee67bf8852011-08-17 17:51:35 -0700786 // If we can treat it as non-range (Jumbo ops will use range form)
787 if (numArgs <= 5)
788 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700789 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700790 /*
791 * Make sure range list doesn't span the break between in normal
792 * Dalvik vRegs and the ins.
793 */
buzbee1b4c8592011-08-31 10:43:51 -0700794 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700795 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700796 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
797 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700798 }
799
800 /*
801 * First load the non-register arguments. Both forms expect all
802 * of the source arguments to be in their home frame location, so
803 * scan the sReg names and flush any that have been promoted to
804 * frame backing storage.
805 */
806 // Scan the rest of the args - if in physReg flush to memory
buzbee0c7f26d2011-09-07 12:28:51 -0700807 for (int i = 3; i < numArgs; i++) {
buzbeee9a72f62011-09-04 17:59:07 -0700808 RegLocation loc = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700809 if (loc.wide) {
810 loc = oatUpdateLocWide(cUnit, loc);
811 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
812 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
813 loc.highReg);
buzbee561227c2011-09-02 15:28:19 -0700814 callState = nextCallInsn(cUnit, mir, dInsn, callState,
815 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700816 }
817 } else {
818 loc = oatUpdateLoc(cUnit, loc);
819 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
820 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700821 callState = nextCallInsn(cUnit, mir, dInsn, callState,
822 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700823 }
buzbee67bf8852011-08-17 17:51:35 -0700824 }
825 }
826
827 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
828 int outsOffset = 4 /* Method* */ + (3 * 4);
829 if (numArgs >= 20) {
830 // Generate memcpy, but first make sure all of
831 opRegRegImm(cUnit, kOpAdd, r0, rSP, startOffset);
832 opRegRegImm(cUnit, kOpAdd, r1, rSP, outsOffset);
833 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
834 loadConstant(cUnit, r2, (numArgs - 3) * 4);
835 newLIR1(cUnit, kThumbBlxR, rLR);
836 } else {
837 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700838 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700839 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700840 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbee1b4c8592011-08-31 10:43:51 -0700841 newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
buzbee561227c2011-09-02 15:28:19 -0700842 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700843 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700844 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700845 newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
buzbee561227c2011-09-02 15:28:19 -0700846 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700847 }
848
849 // Handle the 1st 3 in r1, r2 & r3
buzbeee9a72f62011-09-04 17:59:07 -0700850 for (unsigned int i = 0; i < 3; i++) {
851 if (i < dInsn->vA)
852 registerArgs[i] = dInsn->vC + i;
853 else
854 registerArgs[i] = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700855 }
buzbeee9a72f62011-09-04 17:59:07 -0700856 if (skipThis) {
857 registerArgs[0] = INVALID_REG;
858 }
859 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
860 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700861
buzbee561227c2011-09-02 15:28:19 -0700862 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700863 return callState;
864}
865
buzbee561227c2011-09-02 15:28:19 -0700866static void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
867 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700868{
869 DecodedInstruction* dInsn = &mir->dalvikInsn;
870 int callState = 0;
871 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700872 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700873 NextCallInsn nextCallInsn = nextSDCallInsn;
874
buzbee109bd6a2011-09-06 13:58:41 -0700875 // Explicit register usage
876 oatLockCallTemps(cUnit);
877
buzbee561227c2011-09-02 15:28:19 -0700878 if (range) {
879 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700880 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700881 } else {
882 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700883 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700884 }
buzbee67bf8852011-08-17 17:51:35 -0700885 // Finish up any of the call sequence not interleaved in arg loading
886 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700887 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700888 }
889 newLIR1(cUnit, kThumbBlxR, rLR);
890}
891
buzbee4a3164f2011-09-03 11:25:10 -0700892/*
893 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
894 * which will locate the target and continue on via a tail call.
895 */
buzbee67bf8852011-08-17 17:51:35 -0700896static void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
897{
898 DecodedInstruction* dInsn = &mir->dalvikInsn;
899 int callState = 0;
900 ArmLIR* nullCk;
buzbee109bd6a2011-09-06 13:58:41 -0700901
902 // Explicit register usage
903 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700904 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700905 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700906 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
907 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700908 false, nextInterfaceCallInsn, NULL,
909 true);
buzbee67bf8852011-08-17 17:51:35 -0700910 else
911 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700912 nextInterfaceCallInsn, NULL, true);
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 = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700916 }
917 newLIR1(cUnit, kThumbBlxR, rLR);
918}
919
920static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
921{
922 DecodedInstruction* dInsn = &mir->dalvikInsn;
923 int callState = 0;
924 ArmLIR* nullCk;
buzbee4a3164f2011-09-03 11:25:10 -0700925 ArmLIR* rollback;
926 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
927 Get(dInsn->vB);
928 NextCallInsn nextCallInsn;
929 bool fastPath = true;
buzbee109bd6a2011-09-06 13:58:41 -0700930
931 // Explicit register usage
932 oatLockCallTemps(cUnit);
buzbee6a0f7f52011-09-05 16:14:20 -0700933 if (FORCE_SLOW || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -0700934 fastPath = false;
935 } else {
936 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
937 if (superClass == NULL) {
938 fastPath = false;
939 } else {
940 int32_t target_idx = baseMethod->GetMethodIndex();
941 if (superClass->GetVTable()->GetLength() <= target_idx) {
942 fastPath = false;
943 } else {
944 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
945 }
946 }
947 }
948 if (fastPath) {
949 nextCallInsn = nextSuperCallInsn;
950 rollback = NULL;
951 } else {
952 nextCallInsn = nextSuperCallInsnSP;
953 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
954 rollback->defMask = -1;
955 }
buzbee67bf8852011-08-17 17:51:35 -0700956 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
957 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700958 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700959 else
960 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700961 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700962 // Finish up any of the call sequence not interleaved in arg loading
963 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -0700964 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700965 }
966 newLIR1(cUnit, kThumbBlxR, rLR);
967}
968
969static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
970{
971 DecodedInstruction* dInsn = &mir->dalvikInsn;
972 int callState = 0;
973 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700974 ArmLIR* rollback;
975 Method* method = cUnit->method->GetDexCacheResolvedMethods()->
976 Get(dInsn->vB);
977 NextCallInsn nextCallInsn;
buzbee7b1b86d2011-08-26 18:59:10 -0700978
buzbee109bd6a2011-09-06 13:58:41 -0700979 // Explicit register usage
980 oatLockCallTemps(cUnit);
buzbeee9a72f62011-09-04 17:59:07 -0700981 if (FORCE_SLOW || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -0700982 // Slow path
983 nextCallInsn = nextVCallInsnSP;
984 // If we need a slow-path callout, we'll restart here
985 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
986 rollback->defMask = -1;
987 } else {
988 // Fast path
989 nextCallInsn = nextVCallInsn;
990 rollback = NULL;
991 }
buzbee67bf8852011-08-17 17:51:35 -0700992 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
993 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700994 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700995 else
996 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700997 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700998 // Finish up any of the call sequence not interleaved in arg loading
999 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001000 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001001 }
1002 newLIR1(cUnit, kThumbBlxR, rLR);
1003}
1004
buzbee67bf8852011-08-17 17:51:35 -07001005static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
1006 BasicBlock* bb, ArmLIR* labelList)
1007{
1008 bool res = false; // Assume success
1009 RegLocation rlSrc[3];
1010 RegLocation rlDest = badLoc;
1011 RegLocation rlResult = badLoc;
1012 Opcode opcode = mir->dalvikInsn.opcode;
1013
1014 /* Prep Src and Dest locations */
1015 int nextSreg = 0;
1016 int nextLoc = 0;
1017 int attrs = oatDataFlowAttributes[opcode];
1018 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1019 if (attrs & DF_UA) {
1020 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1021 nextSreg++;
1022 } else if (attrs & DF_UA_WIDE) {
1023 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1024 nextSreg + 1);
1025 nextSreg+= 2;
1026 }
1027 if (attrs & DF_UB) {
1028 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1029 nextSreg++;
1030 } else if (attrs & DF_UB_WIDE) {
1031 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1032 nextSreg + 1);
1033 nextSreg+= 2;
1034 }
1035 if (attrs & DF_UC) {
1036 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1037 } else if (attrs & DF_UC_WIDE) {
1038 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1039 nextSreg + 1);
1040 }
1041 if (attrs & DF_DA) {
1042 rlDest = oatGetDest(cUnit, mir, 0);
1043 } else if (attrs & DF_DA_WIDE) {
1044 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1045 }
1046
1047 switch(opcode) {
1048 case OP_NOP:
1049 break;
1050
1051 case OP_MOVE_EXCEPTION:
1052 int exOffset;
1053 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001054 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001055 resetReg = oatAllocTemp(cUnit);
1056 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1057 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1058 loadConstant(cUnit, resetReg, 0);
1059 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1060 storeValue(cUnit, rlDest, rlResult);
1061 break;
1062
1063 case OP_RETURN_VOID:
1064 break;
1065
1066 case OP_RETURN:
1067 case OP_RETURN_OBJECT:
1068 storeValue(cUnit, retLoc, rlSrc[0]);
1069 break;
1070
1071 case OP_RETURN_WIDE:
1072 rlDest = retLocWide;
1073 rlDest.fp = rlSrc[0].fp;
1074 storeValueWide(cUnit, rlDest, rlSrc[0]);
1075 break;
1076
1077 case OP_MOVE_RESULT_WIDE:
1078 if (mir->OptimizationFlags & MIR_INLINED)
1079 break; // Nop - combined w/ previous invoke
1080 /*
1081 * Somewhat hacky here. Because we're now passing
1082 * return values in registers, we have to let the
1083 * register allocation utilities know that the return
1084 * registers are live and may not be used for address
1085 * formation in storeValueWide.
1086 */
1087 assert(retLocWide.lowReg == r0);
buzbee1da522d2011-09-04 11:22:20 -07001088 assert(retLocWide.highReg == r1);
buzbee67bf8852011-08-17 17:51:35 -07001089 oatLockTemp(cUnit, retLocWide.lowReg);
1090 oatLockTemp(cUnit, retLocWide.highReg);
1091 storeValueWide(cUnit, rlDest, retLocWide);
1092 oatFreeTemp(cUnit, retLocWide.lowReg);
1093 oatFreeTemp(cUnit, retLocWide.highReg);
1094 break;
1095
1096 case OP_MOVE_RESULT:
1097 case OP_MOVE_RESULT_OBJECT:
1098 if (mir->OptimizationFlags & MIR_INLINED)
1099 break; // Nop - combined w/ previous invoke
1100 /* See comment for OP_MOVE_RESULT_WIDE */
1101 assert(retLoc.lowReg == r0);
1102 oatLockTemp(cUnit, retLoc.lowReg);
1103 storeValue(cUnit, rlDest, retLoc);
1104 oatFreeTemp(cUnit, retLoc.lowReg);
1105 break;
1106
1107 case OP_MOVE:
1108 case OP_MOVE_OBJECT:
1109 case OP_MOVE_16:
1110 case OP_MOVE_OBJECT_16:
1111 case OP_MOVE_FROM16:
1112 case OP_MOVE_OBJECT_FROM16:
1113 storeValue(cUnit, rlDest, rlSrc[0]);
1114 break;
1115
1116 case OP_MOVE_WIDE:
1117 case OP_MOVE_WIDE_16:
1118 case OP_MOVE_WIDE_FROM16:
1119 storeValueWide(cUnit, rlDest, rlSrc[0]);
1120 break;
1121
1122 case OP_CONST:
1123 case OP_CONST_4:
1124 case OP_CONST_16:
1125 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1126 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1127 storeValue(cUnit, rlDest, rlResult);
1128 break;
1129
1130 case OP_CONST_HIGH16:
1131 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1132 loadConstantNoClobber(cUnit, rlResult.lowReg,
1133 mir->dalvikInsn.vB << 16);
1134 storeValue(cUnit, rlDest, rlResult);
1135 break;
1136
1137 case OP_CONST_WIDE_16:
1138 case OP_CONST_WIDE_32:
1139 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1140 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1141 //TUNING: do high separately to avoid load dependency
1142 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1143 storeValueWide(cUnit, rlDest, rlResult);
1144 break;
1145
1146 case OP_CONST_WIDE:
1147 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1148 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001149 mir->dalvikInsn.vB_wide & 0xffffffff,
1150 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001151 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001152 break;
1153
1154 case OP_CONST_WIDE_HIGH16:
1155 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1156 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1157 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001158 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001159 break;
1160
1161 case OP_MONITOR_ENTER:
1162 genMonitorEnter(cUnit, mir, rlSrc[0]);
1163 break;
1164
1165 case OP_MONITOR_EXIT:
1166 genMonitorExit(cUnit, mir, rlSrc[0]);
1167 break;
1168
1169 case OP_CHECK_CAST:
1170 genCheckCast(cUnit, mir, rlSrc[0]);
1171 break;
1172
1173 case OP_INSTANCE_OF:
1174 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1175 break;
1176
1177 case OP_NEW_INSTANCE:
1178 genNewInstance(cUnit, mir, rlDest);
1179 break;
1180
1181 case OP_THROW:
1182 genThrow(cUnit, mir, rlSrc[0]);
1183 break;
1184
1185 case OP_ARRAY_LENGTH:
1186 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001187 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001188 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee67bf8852011-08-17 17:51:35 -07001189 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg,
1190 mir->offset, NULL);
1191 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1192 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1193 rlResult.lowReg);
1194 storeValue(cUnit, rlDest, rlResult);
1195 break;
1196
1197 case OP_CONST_STRING:
1198 case OP_CONST_STRING_JUMBO:
1199 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1200 break;
1201
1202 case OP_CONST_CLASS:
1203 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1204 break;
1205
1206 case OP_FILL_ARRAY_DATA:
1207 genFillArrayData(cUnit, mir, rlSrc[0]);
1208 break;
1209
1210 case OP_FILLED_NEW_ARRAY:
1211 genFilledNewArray(cUnit, mir, false /* not range */);
1212 break;
1213
1214 case OP_FILLED_NEW_ARRAY_RANGE:
1215 genFilledNewArray(cUnit, mir, true /* range */);
1216 break;
1217
1218 case OP_NEW_ARRAY:
1219 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1220 break;
1221
1222 case OP_GOTO:
1223 case OP_GOTO_16:
1224 case OP_GOTO_32:
1225 // TUNING: add MIR flag to disable when unnecessary
1226 bool backwardBranch;
1227 backwardBranch = (bb->taken->startOffset <= mir->offset);
1228 if (backwardBranch) {
1229 genSuspendPoll(cUnit, mir);
1230 }
1231 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1232 break;
1233
1234 case OP_PACKED_SWITCH:
1235 genPackedSwitch(cUnit, mir, rlSrc[0]);
1236 break;
1237
1238 case OP_SPARSE_SWITCH:
1239 genSparseSwitch(cUnit, mir, rlSrc[0]);
1240 break;
1241
1242 case OP_CMPL_FLOAT:
1243 case OP_CMPG_FLOAT:
1244 case OP_CMPL_DOUBLE:
1245 case OP_CMPG_DOUBLE:
1246 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1247 break;
1248
1249 case OP_CMP_LONG:
1250 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1251 break;
1252
1253 case OP_IF_EQ:
1254 case OP_IF_NE:
1255 case OP_IF_LT:
1256 case OP_IF_GE:
1257 case OP_IF_GT:
1258 case OP_IF_LE: {
1259 bool backwardBranch;
1260 ArmConditionCode cond;
1261 backwardBranch = (bb->taken->startOffset <= mir->offset);
1262 if (backwardBranch) {
1263 genSuspendPoll(cUnit, mir);
1264 }
1265 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1266 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1267 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1268 switch(opcode) {
1269 case OP_IF_EQ:
1270 cond = kArmCondEq;
1271 break;
1272 case OP_IF_NE:
1273 cond = kArmCondNe;
1274 break;
1275 case OP_IF_LT:
1276 cond = kArmCondLt;
1277 break;
1278 case OP_IF_GE:
1279 cond = kArmCondGe;
1280 break;
1281 case OP_IF_GT:
1282 cond = kArmCondGt;
1283 break;
1284 case OP_IF_LE:
1285 cond = kArmCondLe;
1286 break;
1287 default:
1288 cond = (ArmConditionCode)0;
1289 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1290 }
1291 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1292 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1293 break;
1294 }
1295
1296 case OP_IF_EQZ:
1297 case OP_IF_NEZ:
1298 case OP_IF_LTZ:
1299 case OP_IF_GEZ:
1300 case OP_IF_GTZ:
1301 case OP_IF_LEZ: {
1302 bool backwardBranch;
1303 ArmConditionCode cond;
1304 backwardBranch = (bb->taken->startOffset <= mir->offset);
1305 if (backwardBranch) {
1306 genSuspendPoll(cUnit, mir);
1307 }
1308 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1309 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1310 switch(opcode) {
1311 case OP_IF_EQZ:
1312 cond = kArmCondEq;
1313 break;
1314 case OP_IF_NEZ:
1315 cond = kArmCondNe;
1316 break;
1317 case OP_IF_LTZ:
1318 cond = kArmCondLt;
1319 break;
1320 case OP_IF_GEZ:
1321 cond = kArmCondGe;
1322 break;
1323 case OP_IF_GTZ:
1324 cond = kArmCondGt;
1325 break;
1326 case OP_IF_LEZ:
1327 cond = kArmCondLe;
1328 break;
1329 default:
1330 cond = (ArmConditionCode)0;
1331 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1332 }
1333 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1334 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1335 break;
1336 }
1337
1338 case OP_AGET_WIDE:
1339 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1340 break;
1341 case OP_AGET:
1342 case OP_AGET_OBJECT:
1343 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1344 break;
1345 case OP_AGET_BOOLEAN:
1346 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1347 rlDest, 0);
1348 break;
1349 case OP_AGET_BYTE:
1350 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1351 break;
1352 case OP_AGET_CHAR:
1353 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1354 rlDest, 1);
1355 break;
1356 case OP_AGET_SHORT:
1357 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1358 break;
1359 case OP_APUT_WIDE:
1360 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1361 break;
1362 case OP_APUT:
1363 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1364 break;
1365 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001366 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001367 break;
1368 case OP_APUT_SHORT:
1369 case OP_APUT_CHAR:
1370 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1371 rlSrc[0], 1);
1372 break;
1373 case OP_APUT_BYTE:
1374 case OP_APUT_BOOLEAN:
1375 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1376 rlSrc[0], 0);
1377 break;
1378
1379 case OP_IGET_WIDE:
1380 case OP_IGET_WIDE_VOLATILE:
1381 genIGetWideX(cUnit, mir, rlDest, rlSrc[0]);
1382 break;
1383
1384 case OP_IGET:
1385 case OP_IGET_VOLATILE:
1386 case OP_IGET_OBJECT:
1387 case OP_IGET_OBJECT_VOLATILE:
1388 genIGetX(cUnit, mir, kWord, rlDest, rlSrc[0]);
1389 break;
1390
1391 case OP_IGET_BOOLEAN:
1392 case OP_IGET_BYTE:
1393 genIGetX(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
1394 break;
1395
1396 case OP_IGET_CHAR:
1397 genIGetX(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
1398 break;
1399
1400 case OP_IGET_SHORT:
1401 genIGetX(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
1402 break;
1403
1404 case OP_IPUT_WIDE:
1405 case OP_IPUT_WIDE_VOLATILE:
1406 genIPutWideX(cUnit, mir, rlSrc[0], rlSrc[1]);
1407 break;
1408
1409 case OP_IPUT_OBJECT:
1410 case OP_IPUT_OBJECT_VOLATILE:
1411 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
1412 break;
1413
1414 case OP_IPUT:
1415 case OP_IPUT_VOLATILE:
1416 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
1417 break;
1418
1419 case OP_IPUT_BOOLEAN:
1420 case OP_IPUT_BYTE:
1421 genIPutX(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
1422 break;
1423
1424 case OP_IPUT_CHAR:
1425 genIPutX(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
1426 break;
1427
1428 case OP_IPUT_SHORT:
1429 genIPutX(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
1430 break;
1431
1432 case OP_SGET:
1433 case OP_SGET_OBJECT:
1434 case OP_SGET_BOOLEAN:
1435 case OP_SGET_BYTE:
1436 case OP_SGET_CHAR:
1437 case OP_SGET_SHORT:
1438 genSget(cUnit, mir, rlResult, rlDest);
1439 break;
1440
1441 case OP_SGET_WIDE:
1442 genSgetWide(cUnit, mir, rlResult, rlDest);
1443 break;
1444
1445 case OP_SPUT:
1446 case OP_SPUT_OBJECT:
1447 case OP_SPUT_BOOLEAN:
1448 case OP_SPUT_BYTE:
1449 case OP_SPUT_CHAR:
1450 case OP_SPUT_SHORT:
1451 genSput(cUnit, mir, rlSrc[0]);
1452 break;
1453
1454 case OP_SPUT_WIDE:
1455 genSputWide(cUnit, mir, rlSrc[0]);
1456 break;
1457
1458 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001459 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1460 true /*range*/);
1461 break;
buzbee67bf8852011-08-17 17:51:35 -07001462 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001463 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1464 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001465 break;
1466
1467 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001468 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1469 false /*range*/);
1470 break;
buzbee67bf8852011-08-17 17:51:35 -07001471 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001472 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1473 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001474 break;
1475
1476 case OP_INVOKE_VIRTUAL:
1477 case OP_INVOKE_VIRTUAL_RANGE:
1478 genInvokeVirtual(cUnit, mir);
1479 break;
1480
1481 case OP_INVOKE_SUPER:
1482 case OP_INVOKE_SUPER_RANGE:
1483 genInvokeSuper(cUnit, mir);
1484 break;
1485
1486 case OP_INVOKE_INTERFACE:
1487 case OP_INVOKE_INTERFACE_RANGE:
1488 genInvokeInterface(cUnit, mir);
1489 break;
1490
1491 case OP_NEG_INT:
1492 case OP_NOT_INT:
1493 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1494 break;
1495
1496 case OP_NEG_LONG:
1497 case OP_NOT_LONG:
1498 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1499 break;
1500
1501 case OP_NEG_FLOAT:
1502 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1503 break;
1504
1505 case OP_NEG_DOUBLE:
1506 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1507 break;
1508
1509 case OP_INT_TO_LONG:
1510 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1511 if (rlSrc[0].location == kLocPhysReg) {
1512 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1513 } else {
1514 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1515 }
1516 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1517 rlResult.lowReg, 31);
1518 storeValueWide(cUnit, rlDest, rlResult);
1519 break;
1520
1521 case OP_LONG_TO_INT:
1522 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1523 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1524 storeValue(cUnit, rlDest, rlSrc[0]);
1525 break;
1526
1527 case OP_INT_TO_BYTE:
1528 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1529 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1530 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1531 storeValue(cUnit, rlDest, rlResult);
1532 break;
1533
1534 case OP_INT_TO_SHORT:
1535 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1536 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1537 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1538 storeValue(cUnit, rlDest, rlResult);
1539 break;
1540
1541 case OP_INT_TO_CHAR:
1542 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1543 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1544 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1545 storeValue(cUnit, rlDest, rlResult);
1546 break;
1547
1548 case OP_INT_TO_FLOAT:
1549 case OP_INT_TO_DOUBLE:
1550 case OP_LONG_TO_FLOAT:
1551 case OP_LONG_TO_DOUBLE:
1552 case OP_FLOAT_TO_INT:
1553 case OP_FLOAT_TO_LONG:
1554 case OP_FLOAT_TO_DOUBLE:
1555 case OP_DOUBLE_TO_INT:
1556 case OP_DOUBLE_TO_LONG:
1557 case OP_DOUBLE_TO_FLOAT:
1558 genConversion(cUnit, mir);
1559 break;
1560
1561 case OP_ADD_INT:
1562 case OP_SUB_INT:
1563 case OP_MUL_INT:
1564 case OP_DIV_INT:
1565 case OP_REM_INT:
1566 case OP_AND_INT:
1567 case OP_OR_INT:
1568 case OP_XOR_INT:
1569 case OP_SHL_INT:
1570 case OP_SHR_INT:
1571 case OP_USHR_INT:
1572 case OP_ADD_INT_2ADDR:
1573 case OP_SUB_INT_2ADDR:
1574 case OP_MUL_INT_2ADDR:
1575 case OP_DIV_INT_2ADDR:
1576 case OP_REM_INT_2ADDR:
1577 case OP_AND_INT_2ADDR:
1578 case OP_OR_INT_2ADDR:
1579 case OP_XOR_INT_2ADDR:
1580 case OP_SHL_INT_2ADDR:
1581 case OP_SHR_INT_2ADDR:
1582 case OP_USHR_INT_2ADDR:
1583 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1584 break;
1585
1586 case OP_ADD_LONG:
1587 case OP_SUB_LONG:
1588 case OP_MUL_LONG:
1589 case OP_DIV_LONG:
1590 case OP_REM_LONG:
1591 case OP_AND_LONG:
1592 case OP_OR_LONG:
1593 case OP_XOR_LONG:
1594 case OP_ADD_LONG_2ADDR:
1595 case OP_SUB_LONG_2ADDR:
1596 case OP_MUL_LONG_2ADDR:
1597 case OP_DIV_LONG_2ADDR:
1598 case OP_REM_LONG_2ADDR:
1599 case OP_AND_LONG_2ADDR:
1600 case OP_OR_LONG_2ADDR:
1601 case OP_XOR_LONG_2ADDR:
1602 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1603 break;
1604
buzbee67bf8852011-08-17 17:51:35 -07001605 case OP_SHL_LONG:
1606 case OP_SHR_LONG:
1607 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001608 case OP_SHL_LONG_2ADDR:
1609 case OP_SHR_LONG_2ADDR:
1610 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001611 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1612 break;
1613
1614 case OP_ADD_FLOAT:
1615 case OP_SUB_FLOAT:
1616 case OP_MUL_FLOAT:
1617 case OP_DIV_FLOAT:
1618 case OP_REM_FLOAT:
1619 case OP_ADD_FLOAT_2ADDR:
1620 case OP_SUB_FLOAT_2ADDR:
1621 case OP_MUL_FLOAT_2ADDR:
1622 case OP_DIV_FLOAT_2ADDR:
1623 case OP_REM_FLOAT_2ADDR:
1624 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1625 break;
1626
1627 case OP_ADD_DOUBLE:
1628 case OP_SUB_DOUBLE:
1629 case OP_MUL_DOUBLE:
1630 case OP_DIV_DOUBLE:
1631 case OP_REM_DOUBLE:
1632 case OP_ADD_DOUBLE_2ADDR:
1633 case OP_SUB_DOUBLE_2ADDR:
1634 case OP_MUL_DOUBLE_2ADDR:
1635 case OP_DIV_DOUBLE_2ADDR:
1636 case OP_REM_DOUBLE_2ADDR:
1637 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1638 break;
1639
1640 case OP_RSUB_INT:
1641 case OP_ADD_INT_LIT16:
1642 case OP_MUL_INT_LIT16:
1643 case OP_DIV_INT_LIT16:
1644 case OP_REM_INT_LIT16:
1645 case OP_AND_INT_LIT16:
1646 case OP_OR_INT_LIT16:
1647 case OP_XOR_INT_LIT16:
1648 case OP_ADD_INT_LIT8:
1649 case OP_RSUB_INT_LIT8:
1650 case OP_MUL_INT_LIT8:
1651 case OP_DIV_INT_LIT8:
1652 case OP_REM_INT_LIT8:
1653 case OP_AND_INT_LIT8:
1654 case OP_OR_INT_LIT8:
1655 case OP_XOR_INT_LIT8:
1656 case OP_SHL_INT_LIT8:
1657 case OP_SHR_INT_LIT8:
1658 case OP_USHR_INT_LIT8:
1659 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1660 break;
1661
1662 default:
1663 res = true;
1664 }
1665 return res;
1666}
1667
1668static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1669 "kMirOpPhi",
1670 "kMirOpNullNRangeUpCheck",
1671 "kMirOpNullNRangeDownCheck",
1672 "kMirOpLowerBound",
1673 "kMirOpPunt",
1674 "kMirOpCheckInlinePrediction",
1675};
1676
1677/* Extended MIR instructions like PHI */
1678static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1679{
1680 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1681 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1682 strcpy(msg, extendedMIROpNames[opOffset]);
1683 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1684
1685 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1686 case kMirOpPhi: {
1687 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1688 op->flags.isNop = true;
1689 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1690 break;
1691 }
1692 default:
1693 break;
1694 }
1695}
1696
1697/* If there are any ins passed in registers that have not been promoted
1698 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001699 * Note: at this pointCopy any ins that are passed in register to their
1700 * home location */
buzbee67bf8852011-08-17 17:51:35 -07001701static void flushIns(CompilationUnit* cUnit)
1702{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001703 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001704 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001705 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1706 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001707 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001708 int startLoc = cUnit->method->NumRegisters() -
1709 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001710 for (int i = 0; i < inRegs; i++) {
1711 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001712 //TUNING: be smarter about flushing ins to frame
1713 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001714 if (loc.location == kLocPhysReg) {
1715 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001716 }
1717 }
1718
1719 // Handle special case of wide argument half in regs, half in frame
1720 if (inRegs == 3) {
1721 RegLocation loc = cUnit->regLocation[startLoc + 2];
1722 if (loc.wide && loc.location == kLocPhysReg) {
1723 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001724 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001725 inRegs++;
1726 }
1727 }
1728
1729 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001730 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001731 RegLocation loc = cUnit->regLocation[startLoc + i];
1732 if (loc.fpLocation == kLocPhysReg) {
1733 loc.location = kLocPhysReg;
1734 loc.fp = true;
1735 loc.lowReg = loc.fpLowReg;
1736 loc.highReg = loc.fpHighReg;
1737 }
1738 if (loc.location == kLocPhysReg) {
1739 if (loc.wide) {
1740 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1741 loc.lowReg, loc.highReg, INVALID_SREG);
1742 i++;
1743 } else {
buzbee561227c2011-09-02 15:28:19 -07001744 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001745 }
1746 }
1747 i++;
1748 }
1749}
1750
1751/* Handle the content in each basic block */
1752static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1753{
1754 MIR* mir;
1755 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1756 int blockId = bb->id;
1757
1758 cUnit->curBlock = bb;
1759 labelList[blockId].operands[0] = bb->startOffset;
1760
1761 /* Insert the block label */
1762 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1763 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1764
1765 oatClobberAllRegs(cUnit);
1766 oatResetNullCheck(cUnit);
1767
1768 ArmLIR* headLIR = NULL;
1769
1770 if (bb->blockType == kEntryBlock) {
1771 /*
1772 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1773 * mechanism know so it doesn't try to use any of them when
1774 * expanding the frame or flushing. This leaves the utility
1775 * code with a single temp: r12. This should be enough.
1776 */
1777 oatLockTemp(cUnit, r0);
1778 oatLockTemp(cUnit, r1);
1779 oatLockTemp(cUnit, r2);
1780 oatLockTemp(cUnit, r3);
1781 newLIR0(cUnit, kArmPseudoMethodEntry);
1782 /* Spill core callee saves */
1783 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1784 /* Need to spill any FP regs? */
1785 if (cUnit->numFPSpills) {
1786 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1787 }
1788 opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1789 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1790 flushIns(cUnit);
1791 oatFreeTemp(cUnit, r0);
1792 oatFreeTemp(cUnit, r1);
1793 oatFreeTemp(cUnit, r2);
1794 oatFreeTemp(cUnit, r3);
1795 } else if (bb->blockType == kExitBlock) {
1796 newLIR0(cUnit, kArmPseudoMethodExit);
1797 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1798 /* Need to restore any FP callee saves? */
1799 if (cUnit->numFPSpills) {
1800 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1801 }
1802 if (cUnit->coreSpillMask & (1 << rLR)) {
1803 /* Unspill rLR to rPC */
1804 cUnit->coreSpillMask &= ~(1 << rLR);
1805 cUnit->coreSpillMask |= (1 << rPC);
1806 }
1807 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1808 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1809 /* We didn't pop to rPC, so must do a bv rLR */
1810 newLIR1(cUnit, kThumbBx, rLR);
1811 }
1812 }
1813
1814 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1815
1816 oatResetRegPool(cUnit);
1817 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1818 oatClobberAllRegs(cUnit);
1819 }
1820
1821 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1822 oatResetDefTracking(cUnit);
1823 }
1824
1825 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1826 handleExtendedMethodMIR(cUnit, mir);
1827 continue;
1828 }
1829
1830 cUnit->currentDalvikOffset = mir->offset;
1831
1832 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1833 InstructionFormat dalvikFormat =
1834 dexGetFormatFromOpcode(dalvikOpcode);
1835
1836 ArmLIR* boundaryLIR;
1837
1838 /* Mark the beginning of a Dalvik instruction for line tracking */
1839 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1840 (int) oatGetDalvikDisassembly(
1841 &mir->dalvikInsn, ""));
1842 /* Remember the first LIR for this block */
1843 if (headLIR == NULL) {
1844 headLIR = boundaryLIR;
1845 /* Set the first boundaryLIR as a scheduling barrier */
1846 headLIR->defMask = ENCODE_ALL;
1847 }
1848
1849 /* Don't generate the SSA annotation unless verbose mode is on */
1850 if (cUnit->printMe && mir->ssaRep) {
1851 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1852 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1853 }
1854
1855 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1856
1857 if (notHandled) {
1858 char buf[100];
1859 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1860 mir->offset,
1861 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1862 dalvikFormat);
1863 LOG(FATAL) << buf;
1864 }
1865 }
1866
1867 if (headLIR) {
1868 /*
1869 * Eliminate redundant loads/stores and delay stores into later
1870 * slots
1871 */
1872 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1873 cUnit->lastLIRInsn);
1874
1875 /*
1876 * Generate an unconditional branch to the fallthrough block.
1877 */
1878 if (bb->fallThrough) {
1879 genUnconditionalBranch(cUnit,
1880 &labelList[bb->fallThrough->id]);
1881 }
1882 }
1883 return false;
1884}
1885
1886/*
1887 * Nop any unconditional branches that go to the next instruction.
1888 * Note: new redundant branches may be inserted later, and we'll
1889 * use a check in final instruction assembly to nop those out.
1890 */
1891void removeRedundantBranches(CompilationUnit* cUnit)
1892{
1893 ArmLIR* thisLIR;
1894
1895 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1896 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1897 thisLIR = NEXT_LIR(thisLIR)) {
1898
1899 /* Branch to the next instruction */
1900 if ((thisLIR->opcode == kThumbBUncond) ||
1901 (thisLIR->opcode == kThumb2BUncond)) {
1902 ArmLIR* nextLIR = thisLIR;
1903
1904 while (true) {
1905 nextLIR = NEXT_LIR(nextLIR);
1906
1907 /*
1908 * Is the branch target the next instruction?
1909 */
1910 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1911 thisLIR->flags.isNop = true;
1912 break;
1913 }
1914
1915 /*
1916 * Found real useful stuff between the branch and the target.
1917 * Need to explicitly check the lastLIRInsn here because it
1918 * might be the last real instruction.
1919 */
1920 if (!isPseudoOpcode(nextLIR->opcode) ||
1921 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1922 break;
1923 }
1924 }
1925 }
1926}
1927
1928void oatMethodMIR2LIR(CompilationUnit* cUnit)
1929{
1930 /* Used to hold the labels of each block */
1931 cUnit->blockLabelList =
1932 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
1933
1934 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
1935 kPreOrderDFSTraversal, false /* Iterative */);
1936 removeRedundantBranches(cUnit);
1937}
1938
1939/* Common initialization routine for an architecture family */
1940bool oatArchInit()
1941{
1942 int i;
1943
1944 for (i = 0; i < kArmLast; i++) {
1945 if (EncodingMap[i].opcode != i) {
1946 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
1947 " is wrong: expecting " << i << ", seeing " <<
1948 (int)EncodingMap[i].opcode;
1949 }
1950 }
1951
1952 return oatArchVariantInit();
1953}
1954
1955/* Needed by the Assembler */
1956void oatSetupResourceMasks(ArmLIR* lir)
1957{
1958 setupResourceMasks(lir);
1959}
1960
1961/* Needed by the ld/st optmizatons */
1962ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
1963{
1964 return genRegCopyNoInsert(cUnit, rDest, rSrc);
1965}
1966
1967/* Needed by the register allocator */
1968ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
1969{
1970 return genRegCopy(cUnit, rDest, rSrc);
1971}
1972
1973/* Needed by the register allocator */
1974void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
1975 int srcLo, int srcHi)
1976{
1977 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
1978}
1979
1980void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
1981 int displacement, int rSrc, OpSize size)
1982{
1983 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
1984}
1985
1986void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
1987 int displacement, int rSrcLo, int rSrcHi)
1988{
1989 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
1990}