blob: 2319a712e980a7a4797de3329b18338c986b329a [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
buzbee67bf8852011-08-17 17:51:35 -070017static const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
18 INVALID_REG, INVALID_SREG, 0,
19 kLocDalvikFrame, INVALID_REG, INVALID_REG,
20 INVALID_OFFSET};
21static const RegLocation retLoc = LOC_DALVIK_RETURN_VAL;
22static const RegLocation retLocWide = LOC_DALVIK_RETURN_VAL_WIDE;
23
buzbeedfd3d702011-08-28 12:56:51 -070024/*
25 * Let helper function take care of everything. Will call
26 * Array::AllocFromCode(type_idx, method, count);
27 * Note: AllocFromCode will handle checks for errNegativeArraySize.
28 */
buzbee67bf8852011-08-17 17:51:35 -070029static void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
30 RegLocation rlSrc)
31{
buzbeedfd3d702011-08-28 12:56:51 -070032 oatFlushAllRegs(cUnit); /* Everything to home location */
33 loadWordDisp(cUnit, rSELF,
34 OFFSETOF_MEMBER(Thread, pAllocFromCode), rLR);
35 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
36 loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
37 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
38 opReg(cUnit, kOpBlx, rLR);
39 oatClobberCallRegs(cUnit);
40 RegLocation rlResult = oatGetReturn(cUnit);
41 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070042}
43
44/*
45 * Similar to genNewArray, but with post-allocation initialization.
46 * Verifier guarantees we're dealing with an array class. Current
47 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
48 * Current code also throws internal unimp if not 'L', '[' or 'I'.
49 */
50static void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
51{
52 DecodedInstruction* dInsn = &mir->dalvikInsn;
53 int elems;
buzbeedfd3d702011-08-28 12:56:51 -070054 int typeId;
buzbee67bf8852011-08-17 17:51:35 -070055 if (isRange) {
56 elems = dInsn->vA;
buzbeedfd3d702011-08-28 12:56:51 -070057 typeId = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -070058 } else {
59 elems = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070060 typeId = dInsn->vC;
buzbee67bf8852011-08-17 17:51:35 -070061 }
buzbeedfd3d702011-08-28 12:56:51 -070062 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070063 loadWordDisp(cUnit, rSELF,
buzbee1da522d2011-09-04 11:22:20 -070064 OFFSETOF_MEMBER(Thread, pCheckAndAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070065 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
66 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
67 loadConstant(cUnit, r2, elems); // arg2 <- count
68 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -070069 /*
buzbeedfd3d702011-08-28 12:56:51 -070070 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
71 * return region. Because AllocFromCode placed the new array
72 * in r0, we'll just lock it into place. When debugger support is
73 * added, it may be necessary to additionally copy all return
74 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070075 */
buzbee67bf8852011-08-17 17:51:35 -070076 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070077
buzbee67bf8852011-08-17 17:51:35 -070078 // Having a range of 0 is legal
79 if (isRange && (dInsn->vA > 0)) {
80 /*
81 * Bit of ugliness here. We're going generate a mem copy loop
82 * on the register range, but it is possible that some regs
83 * in the range have been promoted. This is unlikely, but
84 * before generating the copy, we'll just force a flush
85 * of any regs in the source range that have been promoted to
86 * home location.
87 */
88 for (unsigned int i = 0; i < dInsn->vA; i++) {
89 RegLocation loc = oatUpdateLoc(cUnit,
90 oatGetSrc(cUnit, mir, i));
91 if (loc.location == kLocPhysReg) {
92 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
93 }
94 }
95 /*
96 * TUNING note: generated code here could be much improved, but
97 * this is an uncommon operation and isn't especially performance
98 * critical.
99 */
100 int rSrc = oatAllocTemp(cUnit);
101 int rDst = oatAllocTemp(cUnit);
102 int rIdx = oatAllocTemp(cUnit);
103 int rVal = rLR; // Using a lot of temps, rLR is known free here
104 // Set up source pointer
105 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
106 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
107 // Set up the target pointer
108 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700109 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700110 // Set up the loop counter (known to be > 0)
111 loadConstant(cUnit, rIdx, dInsn->vA);
112 // Generate the copy loop. Going backwards for convenience
113 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
114 target->defMask = ENCODE_ALL;
115 // Copy next element
116 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
117 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
118 // Use setflags encoding here
119 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
120 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
121 branch->generic.target = (LIR*)target;
122 } else if (!isRange) {
123 // TUNING: interleave
124 for (unsigned int i = 0; i < dInsn->vA; i++) {
125 RegLocation rlArg = loadValue(cUnit,
126 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700127 storeBaseDisp(cUnit, r0,
128 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700129 i * 4, rlArg.lowReg, kWord);
130 // If the loadValue caused a temp to be allocated, free it
131 if (oatIsTemp(cUnit, rlArg.lowReg)) {
132 oatFreeTemp(cUnit, rlArg.lowReg);
133 }
134 }
135 }
136}
137
138static void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
139{
buzbeee1931742011-08-28 21:15:53 -0700140 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
141 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700142 int fieldIdx = mir->dalvikInsn.vB;
143 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
144 if (field == NULL) {
145 // Slow path
buzbee34cd9e52011-09-08 14:31:52 -0700146 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
147 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700148 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);
buzbee34cd9e52011-09-08 14:31:52 -0700205 if (SLOW_FIELD_PATH || field == NULL) {
206 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
207 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700208 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700209 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700210 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
211 loadCurrMethodDirect(cUnit, r1);
212 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
213 opReg(cUnit, kOpBlx, rLR);
214 oatClobberCallRegs(cUnit);
215 } else {
buzbee1da522d2011-09-04 11:22:20 -0700216 // fast path
217 int fieldOffset = field->GetOffset().Int32Value();
218 art::ClassLinker* class_linker = art::Runtime::Current()->
219 GetClassLinker();
220 const art::DexFile& dex_file = class_linker->
221 FindDexFile(field->GetDeclaringClass()->GetDexCache());
222 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
223 int typeIdx = field_id.class_idx_;
224 // Using fixed register to sync with slow path
225 int rMethod = r1;
226 oatLockTemp(cUnit, rMethod);
227 loadCurrMethodDirect(cUnit, r1);
228 int rBase = r0;
229 oatLockTemp(cUnit, rBase);
230 loadWordDisp(cUnit, rMethod,
231 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
232 rBase);
233 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
234 sizeof(int32_t*)* typeIdx, rBase);
235 // TUNING: fast path should fall through
236 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
237 loadWordDisp(cUnit, rSELF,
238 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
239 loadConstant(cUnit, r0, typeIdx);
240 opReg(cUnit, kOpBlx, rLR);
241 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
242 skipTarget->defMask = ENCODE_ALL;
243 branchOver->generic.target = (LIR*)skipTarget;
244 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
245 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
246 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
247 rlSrc.highReg);
248#if ANDROID_SMP != 0
249 if (field->IsVolatile()) {
250 oatGenMemBarrier(cUnit, kSY);
251 }
buzbeec143c552011-08-20 17:38:58 -0700252#endif
buzbee1da522d2011-09-04 11:22:20 -0700253 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700254 }
buzbee67bf8852011-08-17 17:51:35 -0700255}
256
257
buzbee67bf8852011-08-17 17:51:35 -0700258static void genSgetWide(CompilationUnit* cUnit, MIR* mir,
259 RegLocation rlResult, RegLocation rlDest)
260{
buzbee1da522d2011-09-04 11:22:20 -0700261 int fieldIdx = mir->dalvikInsn.vB;
262 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700263 if (SLOW_FIELD_PATH || field == NULL) {
264 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
265 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700266 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700267 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700268 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
269 loadCurrMethodDirect(cUnit, r1);
270 opReg(cUnit, kOpBlx, rLR);
271 RegLocation rlResult = oatGetReturnWide(cUnit);
272 storeValueWide(cUnit, rlDest, rlResult);
273 } else {
buzbee1da522d2011-09-04 11:22:20 -0700274 // Fast path
275 int fieldOffset = field->GetOffset().Int32Value();
276 art::ClassLinker* class_linker = art::Runtime::Current()->
277 GetClassLinker();
278 const art::DexFile& dex_file = class_linker->
279 FindDexFile(field->GetDeclaringClass()->GetDexCache());
280 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
281 int typeIdx = field_id.class_idx_;
282 // Using fixed register to sync with slow path
283 int rMethod = r1;
284 oatLockTemp(cUnit, rMethod);
285 loadCurrMethodDirect(cUnit, rMethod);
286 int rBase = r0;
287 oatLockTemp(cUnit, rBase);
288 loadWordDisp(cUnit, rMethod,
289 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
290 rBase);
291 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
292 sizeof(int32_t*)* typeIdx, rBase);
293 // TUNING: fast path should fall through
294 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
295 loadWordDisp(cUnit, rSELF,
296 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
297 loadConstant(cUnit, r0, typeIdx);
298 opReg(cUnit, kOpBlx, rLR);
299 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
300 skipTarget->defMask = ENCODE_ALL;
301 branchOver->generic.target = (LIR*)skipTarget;
302 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
303 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
304#if ANDROID_SMP != 0
305 if (isVolatile) {
306 oatGenMemBarrier(cUnit, kSY);
307 }
buzbeec143c552011-08-20 17:38:58 -0700308#endif
buzbee1da522d2011-09-04 11:22:20 -0700309 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
310 rlResult.highReg, INVALID_SREG);
311 oatFreeTemp(cUnit, rBase);
312 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700313 }
buzbee67bf8852011-08-17 17:51:35 -0700314}
315
316static void genSget(CompilationUnit* cUnit, MIR* mir,
317 RegLocation rlResult, RegLocation rlDest)
318{
buzbee1da522d2011-09-04 11:22:20 -0700319 int fieldIdx = mir->dalvikInsn.vB;
320 Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
buzbeee1931742011-08-28 21:15:53 -0700321 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
322 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee34cd9e52011-09-08 14:31:52 -0700323 if (SLOW_FIELD_PATH || field == NULL) {
324 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
325 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700326 // Slow path
327 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
328 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700329 oatFlushAllRegs(cUnit);
330 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
331 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
332 loadCurrMethodDirect(cUnit, r1);
333 opReg(cUnit, kOpBlx, rLR);
334 RegLocation rlResult = oatGetReturn(cUnit);
335 storeValue(cUnit, rlDest, rlResult);
336 } else {
buzbee1da522d2011-09-04 11:22:20 -0700337 // Fast path
338 int fieldOffset = field->GetOffset().Int32Value();
339 art::ClassLinker* class_linker = art::Runtime::Current()->
340 GetClassLinker();
341 const art::DexFile& dex_file = class_linker->
342 FindDexFile(field->GetDeclaringClass()->GetDexCache());
343 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
344 int typeIdx = field_id.class_idx_;
345 // Using fixed register to sync with slow path
346 int rMethod = r1;
347 oatLockTemp(cUnit, rMethod);
348 loadCurrMethodDirect(cUnit, rMethod);
349 int rBase = r0;
350 oatLockTemp(cUnit, rBase);
351 loadWordDisp(cUnit, rMethod,
352 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
353 rBase);
354 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
355 sizeof(int32_t*)* typeIdx, rBase);
356 // TUNING: fast path should fall through
357 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
358 loadWordDisp(cUnit, rSELF,
359 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
360 loadConstant(cUnit, r0, typeIdx);
361 opReg(cUnit, kOpBlx, rLR);
362 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
363 skipTarget->defMask = ENCODE_ALL;
364 branchOver->generic.target = (LIR*)skipTarget;
365 rlDest = oatGetDest(cUnit, mir, 0);
366 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700367#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700368 if (isVolatile) {
369 oatGenMemBarrier(cUnit, kSY);
370 }
buzbee67bf8852011-08-17 17:51:35 -0700371#endif
buzbee1da522d2011-09-04 11:22:20 -0700372 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
373 oatFreeTemp(cUnit, rBase);
374 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700375 }
buzbee67bf8852011-08-17 17:51:35 -0700376}
377
buzbee561227c2011-09-02 15:28:19 -0700378typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
379 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700380
381/*
382 * Bit of a hack here - in leiu of a real scheduling pass,
383 * emit the next instruction in static & direct invoke sequences.
384 */
385static int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700386 DecodedInstruction* dInsn, int state,
387 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700388{
buzbee561227c2011-09-02 15:28:19 -0700389 DCHECK(rollback == NULL);
390 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700391 switch(state) {
392 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700393 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700394 break;
buzbee561227c2011-09-02 15:28:19 -0700395 case 1: // Get method->code_and_direct_methods_
396 loadWordDisp(cUnit, r0,
397 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
398 r0);
buzbee67bf8852011-08-17 17:51:35 -0700399 break;
buzbee561227c2011-09-02 15:28:19 -0700400 case 2: // Grab target method* and target code_
401 loadWordDisp(cUnit, r0,
402 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
403 loadWordDisp(cUnit, r0,
404 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700405 break;
406 default:
407 return -1;
408 }
409 return state + 1;
410}
411
buzbee67bf8852011-08-17 17:51:35 -0700412/*
413 * Bit of a hack here - in leiu of a real scheduling pass,
414 * emit the next instruction in a virtual invoke sequence.
415 * We can use rLR as a temp prior to target address loading
416 * Note also that we'll load the first argument ("this") into
417 * r1 here rather than the standard loadArgRegs.
418 */
419static int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700420 DecodedInstruction* dInsn, int state,
421 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700422{
buzbee561227c2011-09-02 15:28:19 -0700423 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700424 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700425 /*
426 * This is the fast path in which the target virtual method is
427 * fully resolved at compile time.
428 */
429 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
430 Get(dInsn->vB);
431 CHECK(baseMethod != NULL);
432 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700433 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700434 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700435 rlArg = oatGetSrc(cUnit, mir, 0);
436 loadValueDirectFixed(cUnit, rlArg, r1);
437 break;
buzbee561227c2011-09-02 15:28:19 -0700438 case 1: // Is "this" null? [use r1]
439 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
440 // get this->klass_ [use r1, set rLR]
441 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700442 break;
buzbee561227c2011-09-02 15:28:19 -0700443 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
444 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700445 break;
buzbee561227c2011-09-02 15:28:19 -0700446 case 3: // Get target method [use rLR, set r0]
447 loadWordDisp(cUnit, rLR, (target_idx * 4) +
448 art::Array::DataOffset().Int32Value(), r0);
449 break;
450 case 4: // Get the target compiled code address [uses r0, sets rLR]
451 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700452 break;
453 default:
454 return -1;
455 }
456 return state + 1;
457}
458
buzbee7b1b86d2011-08-26 18:59:10 -0700459static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700460 DecodedInstruction* dInsn, int state,
461 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700462{
buzbee561227c2011-09-02 15:28:19 -0700463 DCHECK(rollback != NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700464 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700465 ArmLIR* skipBranch;
466 ArmLIR* skipTarget;
467 /*
468 * This handles the case in which the base method is not fully
469 * resolved at compile time. We must generate code to test
470 * for resolution a run time, bail to the slow path if not to
471 * fill in all the tables. In the latter case, we'll restart at
472 * at the beginning of the sequence.
473 */
buzbee7b1b86d2011-08-26 18:59:10 -0700474 switch(state) {
475 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700476 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700477 break;
buzbee561227c2011-09-02 15:28:19 -0700478 case 1: // Get method->dex_cache_resolved_methods_
479 loadWordDisp(cUnit, r0,
480 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700481 break;
buzbee561227c2011-09-02 15:28:19 -0700482 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
483 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
484 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700485 break;
buzbee561227c2011-09-02 15:28:19 -0700486 case 3: // Resolved?
487 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
488 // Slowest path, bail to helper, rollback and retry
489 loadWordDisp(cUnit, rSELF,
490 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
491 loadConstant(cUnit, r1, dInsn->vB);
492 newLIR1(cUnit, kThumbBlxR, rLR);
493 genUnconditionalBranch(cUnit, rollback);
494 // Resume normal slow path
495 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
496 skipTarget->defMask = ENCODE_ALL;
497 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700498 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700499 loadBaseDisp(cUnit, mir, rLR,
500 Method::GetMethodIndexOffset().Int32Value(), r0,
501 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700502 // Load "this" [set r1]
503 rlArg = oatGetSrc(cUnit, mir, 0);
504 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700505 break;
506 case 4:
507 // Is "this" null? [use r1]
508 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
509 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700510 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700511 break;
buzbee561227c2011-09-02 15:28:19 -0700512 case 5:
513 // get this->klass_->vtable_ [usr rLR, set rLR]
514 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
515 DCHECK((art::Array::DataOffset().Int32Value() & 0x3) == 0);
516 // In load shadow fold vtable_ object header size into method_index_
517 opRegImm(cUnit, kOpAdd, r0,
518 art::Array::DataOffset().Int32Value() / 4);
519 // Get target Method*
520 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
521 break;
522 case 6: // Get the target compiled code address [uses r0, sets rLR]
523 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700524 break;
525 default:
526 return -1;
527 }
528 return state + 1;
529}
530
buzbee67bf8852011-08-17 17:51:35 -0700531/* Load up to 3 arguments in r1..r3 */
532static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
533 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700534 int *args, NextCallInsn nextCallInsn, ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700535{
536 for (int i = 0; i < 3; i++) {
537 if (args[i] != INVALID_REG) {
buzbee1b4c8592011-08-31 10:43:51 -0700538 // Arguments are treated as a series of untyped 32-bit values.
buzbeee9a72f62011-09-04 17:59:07 -0700539 RegLocation rlArg = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700540 rlArg.wide = false;
buzbee67bf8852011-08-17 17:51:35 -0700541 loadValueDirectFixed(cUnit, rlArg, r1 + i);
buzbee561227c2011-09-02 15:28:19 -0700542 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700543 }
544 }
545 return callState;
546}
547
buzbee4a3164f2011-09-03 11:25:10 -0700548// Interleave launch code for INVOKE_INTERFACE.
buzbee67bf8852011-08-17 17:51:35 -0700549static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700550 DecodedInstruction* dInsn, int state,
551 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700552{
buzbee67bf8852011-08-17 17:51:35 -0700553 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700554 case 0: // Load trampoline target
555 loadWordDisp(cUnit, rSELF,
556 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
557 rLR);
558 // Load r0 with method index
559 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700560 break;
buzbee67bf8852011-08-17 17:51:35 -0700561 default:
562 return -1;
563 }
564 return state + 1;
565}
566
buzbee67bf8852011-08-17 17:51:35 -0700567/*
568 * Interleave launch code for INVOKE_SUPER. See comments
569 * for nextVCallIns.
570 */
571static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700572 DecodedInstruction* dInsn, int state,
573 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700574{
buzbee4a3164f2011-09-03 11:25:10 -0700575 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700576 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700577 /*
578 * This is the fast path in which the target virtual method is
579 * fully resolved at compile time. Note also that this path assumes
580 * that the check to verify that the target method index falls
581 * within the size of the super's vtable has been done at compile-time.
582 */
583 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
584 Get(dInsn->vB);
585 CHECK(baseMethod != NULL);
586 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
587 CHECK(superClass != NULL);
588 int32_t target_idx = baseMethod->GetMethodIndex();
589 CHECK(superClass->GetVTable()->GetLength() > target_idx);
590 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
591 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700592 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700593 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700594 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700595 // Load "this" [set r1]
596 rlArg = oatGetSrc(cUnit, mir, 0);
597 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700598 // Get method->declaring_class_ [use r0, set rLR]
599 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
600 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700601 // Is "this" null? [use r1]
602 genNullCheck(cUnit, oatSSASrc(mir,0), r1,
603 mir->offset, NULL);
buzbee4a3164f2011-09-03 11:25:10 -0700604 break;
605 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
606 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
607 rLR);
608 break;
609 case 2: // Get ...->super_class_->vtable [u/s rLR]
610 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
611 break;
612 case 3: // Get target method [use rLR, set r0]
613 loadWordDisp(cUnit, rLR, (target_idx * 4) +
614 art::Array::DataOffset().Int32Value(), r0);
615 break;
616 case 4: // Get the target compiled code address [uses r0, sets rLR]
617 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
618 break;
buzbee67bf8852011-08-17 17:51:35 -0700619 default:
620 return -1;
621 }
buzbee4a3164f2011-09-03 11:25:10 -0700622 return state + 1;
623}
624
625/* Slow-path version of nextSuperCallInsn */
626static int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
627 DecodedInstruction* dInsn, int state,
628 ArmLIR* rollback)
629{
630 DCHECK(rollback != NULL);
631 RegLocation rlArg;
632 ArmLIR* skipBranch;
633 ArmLIR* skipTarget;
634 int tReg;
635 /*
636 * This handles the case in which the base method is not fully
637 * resolved at compile time. We must generate code to test
638 * for resolution a run time, bail to the slow path if not to
639 * fill in all the tables. In the latter case, we'll restart at
640 * at the beginning of the sequence.
641 */
642 switch(state) {
643 case 0: // Get the current Method* [sets r0]
644 loadCurrMethodDirect(cUnit, r0);
645 break;
646 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
647 loadWordDisp(cUnit, r0,
648 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
649 break;
650 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
651 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
652 art::Array::DataOffset().Int32Value(), rLR);
653 break;
654 case 3: // Resolved?
655 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
656 // Slowest path, bail to helper, rollback and retry
657 loadWordDisp(cUnit, rSELF,
658 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
659 loadConstant(cUnit, r1, dInsn->vB);
660 newLIR1(cUnit, kThumbBlxR, rLR);
661 genUnconditionalBranch(cUnit, rollback);
662 // Resume normal slow path
663 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
664 skipTarget->defMask = ENCODE_ALL;
665 skipBranch->generic.target = (LIR*)skipTarget;
666 // Get base_method->method_index [usr rLR, set rLR]
667 loadBaseDisp(cUnit, mir, rLR,
668 Method::GetMethodIndexOffset().Int32Value(), rLR,
669 kUnsignedHalf, INVALID_SREG);
670 // Load "this" [set r1]
671 rlArg = oatGetSrc(cUnit, mir, 0);
672 loadValueDirectFixed(cUnit, rlArg, r1);
673 // Load curMethod->declaring_class_ [uses r0, sets r0]
674 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
675 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700676 // Null this?
677 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
678 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700679 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
680 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700681 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700682 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee4a3164f2011-09-03 11:25:10 -0700683 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
684 // Range check, throw NSM on failure
685 tReg = oatAllocTemp(cUnit);
686 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
687 tReg);
688 genBoundsCheck(cUnit, tReg, rLR, mir->offset, NULL);
689 oatFreeTemp(cUnit, tReg);
690 }
buzbee6a0f7f52011-09-05 16:14:20 -0700691 // Adjust vtable_ base past object header
692 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700693 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700694 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700695 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700696 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700697 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
698 break;
699 default:
700 return -1;
701 }
buzbee67bf8852011-08-17 17:51:35 -0700702 return state + 1;
703}
704
705/*
706 * Load up to 5 arguments, the first three of which will be in
707 * r1 .. r3. On entry r0 contains the current method pointer,
708 * and as part of the load sequence, it must be replaced with
709 * the target method pointer. Note, this may also be called
710 * for "range" variants if the number of arguments is 5 or fewer.
711 */
712static int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
713 DecodedInstruction* dInsn, int callState,
714 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700715 NextCallInsn nextCallInsn, ArmLIR* rollback,
716 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700717{
718 RegLocation rlArg;
719 int registerArgs[3];
720
721 /* If no arguments, just return */
722 if (dInsn->vA == 0)
723 return callState;
724
buzbee561227c2011-09-02 15:28:19 -0700725 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700726
727 /*
728 * Load frame arguments arg4 & arg5 first. Coded a little odd to
729 * pre-schedule the method pointer target.
730 */
731 for (unsigned int i=3; i < dInsn->vA; i++) {
732 int reg;
buzbeee9a72f62011-09-04 17:59:07 -0700733 rlArg = oatUpdateLoc(cUnit, oatGetSrc(cUnit, mir, i));
buzbee67bf8852011-08-17 17:51:35 -0700734 if (rlArg.location == kLocPhysReg) {
735 reg = rlArg.lowReg;
736 } else {
buzbee109bd6a2011-09-06 13:58:41 -0700737 // r3 is the last arg register loaded, so can safely be used here
738 reg = r3;
739 loadValueDirectFixed(cUnit, rlArg, reg);
buzbee561227c2011-09-02 15:28:19 -0700740 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700741 }
742 storeBaseDisp(cUnit, rSP, (i + 1) * 4, reg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700743 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700744 }
745
746 /* Load register arguments r1..r3 */
buzbeee9a72f62011-09-04 17:59:07 -0700747 for (unsigned int i = 0; i < 3; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700748 if (i < dInsn->vA)
749 registerArgs[i] = (isRange) ? dInsn->vC + i : i;
750 else
751 registerArgs[i] = INVALID_REG;
752 }
buzbeee9a72f62011-09-04 17:59:07 -0700753 if (skipThis) {
754 registerArgs[0] = INVALID_REG;
755 }
buzbee67bf8852011-08-17 17:51:35 -0700756 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
buzbee561227c2011-09-02 15:28:19 -0700757 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700758
buzbee6a0f7f52011-09-05 16:14:20 -0700759 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700760 // Load direct & need a "this" null check?
761 if (pcrLabel) {
762 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1,
763 mir->offset, NULL);
764 }
765 return callState;
766}
767
768/*
769 * May have 0+ arguments (also used for jumbo). Note that
770 * source virtual registers may be in physical registers, so may
771 * need to be flushed to home location before copying. This
772 * applies to arg3 and above (see below).
773 *
774 * Two general strategies:
775 * If < 20 arguments
776 * Pass args 3-18 using vldm/vstm block copy
777 * Pass arg0, arg1 & arg2 in r1-r3
778 * If 20+ arguments
779 * Pass args arg19+ using memcpy block copy
780 * Pass arg0, arg1 & arg2 in r1-r3
781 *
782 */
783static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
784 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700785 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700786 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700787{
788 int firstArg = dInsn->vC;
789 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700790 int registerArgs[3];
791
buzbee67bf8852011-08-17 17:51:35 -0700792 // If we can treat it as non-range (Jumbo ops will use range form)
793 if (numArgs <= 5)
794 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700795 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700796 /*
797 * Make sure range list doesn't span the break between in normal
798 * Dalvik vRegs and the ins.
799 */
buzbee1b4c8592011-08-31 10:43:51 -0700800 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700801 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700802 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
803 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700804 }
805
806 /*
807 * First load the non-register arguments. Both forms expect all
808 * of the source arguments to be in their home frame location, so
809 * scan the sReg names and flush any that have been promoted to
810 * frame backing storage.
811 */
812 // Scan the rest of the args - if in physReg flush to memory
buzbee0c7f26d2011-09-07 12:28:51 -0700813 for (int i = 3; i < numArgs; i++) {
buzbeee9a72f62011-09-04 17:59:07 -0700814 RegLocation loc = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700815 if (loc.wide) {
816 loc = oatUpdateLocWide(cUnit, loc);
817 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
818 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
819 loc.highReg);
buzbee561227c2011-09-02 15:28:19 -0700820 callState = nextCallInsn(cUnit, mir, dInsn, callState,
821 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700822 }
823 } else {
824 loc = oatUpdateLoc(cUnit, loc);
825 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
826 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700827 callState = nextCallInsn(cUnit, mir, dInsn, callState,
828 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700829 }
buzbee67bf8852011-08-17 17:51:35 -0700830 }
831 }
832
833 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
834 int outsOffset = 4 /* Method* */ + (3 * 4);
835 if (numArgs >= 20) {
836 // Generate memcpy, but first make sure all of
837 opRegRegImm(cUnit, kOpAdd, r0, rSP, startOffset);
838 opRegRegImm(cUnit, kOpAdd, r1, rSP, outsOffset);
839 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
840 loadConstant(cUnit, r2, (numArgs - 3) * 4);
841 newLIR1(cUnit, kThumbBlxR, rLR);
842 } else {
843 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700844 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700845 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700846 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbee1b4c8592011-08-31 10:43:51 -0700847 newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
buzbee561227c2011-09-02 15:28:19 -0700848 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700849 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700850 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700851 newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
buzbee561227c2011-09-02 15:28:19 -0700852 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700853 }
854
855 // Handle the 1st 3 in r1, r2 & r3
buzbeee9a72f62011-09-04 17:59:07 -0700856 for (unsigned int i = 0; i < 3; i++) {
857 if (i < dInsn->vA)
858 registerArgs[i] = dInsn->vC + i;
859 else
860 registerArgs[i] = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700861 }
buzbeee9a72f62011-09-04 17:59:07 -0700862 if (skipThis) {
863 registerArgs[0] = INVALID_REG;
864 }
865 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
866 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700867
buzbee561227c2011-09-02 15:28:19 -0700868 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700869 return callState;
870}
871
buzbee2a475e72011-09-07 17:19:17 -0700872#ifdef DISPLAY_MISSING_TARGETS
873// Debugging routine - if null target, branch to DebugMe
874static void genShowTarget(CompilationUnit* cUnit)
875{
876 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
877 loadWordDisp(cUnit, rSELF,
878 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
879 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
880 target->defMask = -1;
881 branchOver->generic.target = (LIR*)target;
882}
883#endif
884
buzbee561227c2011-09-02 15:28:19 -0700885static void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
886 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700887{
888 DecodedInstruction* dInsn = &mir->dalvikInsn;
889 int callState = 0;
890 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700891 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700892 NextCallInsn nextCallInsn = nextSDCallInsn;
893
buzbee109bd6a2011-09-06 13:58:41 -0700894 // Explicit register usage
895 oatLockCallTemps(cUnit);
896
buzbee561227c2011-09-02 15:28:19 -0700897 if (range) {
898 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700899 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700900 } else {
901 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700902 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700903 }
buzbee67bf8852011-08-17 17:51:35 -0700904 // Finish up any of the call sequence not interleaved in arg loading
905 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700906 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700907 }
buzbee2a475e72011-09-07 17:19:17 -0700908#ifdef DISPLAY_MISSING_TARGETS
909 genShowTarget(cUnit);
910#endif
buzbee67bf8852011-08-17 17:51:35 -0700911 newLIR1(cUnit, kThumbBlxR, rLR);
912}
913
buzbee4a3164f2011-09-03 11:25:10 -0700914/*
915 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
916 * which will locate the target and continue on via a tail call.
917 */
buzbee67bf8852011-08-17 17:51:35 -0700918static void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
919{
920 DecodedInstruction* dInsn = &mir->dalvikInsn;
921 int callState = 0;
922 ArmLIR* nullCk;
buzbee109bd6a2011-09-06 13:58:41 -0700923
924 // Explicit register usage
925 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700926 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700927 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700928 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
929 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700930 false, nextInterfaceCallInsn, NULL,
931 true);
buzbee67bf8852011-08-17 17:51:35 -0700932 else
933 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700934 nextInterfaceCallInsn, NULL, true);
buzbee67bf8852011-08-17 17:51:35 -0700935 // Finish up any of the call sequence not interleaved in arg loading
936 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700937 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700938 }
buzbee2a475e72011-09-07 17:19:17 -0700939#ifdef DISPLAY_MISSING_TARGETS
940 genShowTarget(cUnit);
941#endif
buzbee67bf8852011-08-17 17:51:35 -0700942 newLIR1(cUnit, kThumbBlxR, rLR);
943}
944
945static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
946{
947 DecodedInstruction* dInsn = &mir->dalvikInsn;
948 int callState = 0;
949 ArmLIR* nullCk;
buzbee4a3164f2011-09-03 11:25:10 -0700950 ArmLIR* rollback;
951 Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
952 Get(dInsn->vB);
953 NextCallInsn nextCallInsn;
954 bool fastPath = true;
buzbee109bd6a2011-09-06 13:58:41 -0700955
956 // Explicit register usage
957 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700958 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -0700959 fastPath = false;
960 } else {
961 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
962 if (superClass == NULL) {
963 fastPath = false;
964 } else {
965 int32_t target_idx = baseMethod->GetMethodIndex();
966 if (superClass->GetVTable()->GetLength() <= target_idx) {
967 fastPath = false;
968 } else {
969 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
970 }
971 }
972 }
973 if (fastPath) {
974 nextCallInsn = nextSuperCallInsn;
975 rollback = NULL;
976 } else {
977 nextCallInsn = nextSuperCallInsnSP;
978 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
979 rollback->defMask = -1;
980 }
buzbee67bf8852011-08-17 17:51:35 -0700981 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
982 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700983 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700984 else
985 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700986 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -0700987 // Finish up any of the call sequence not interleaved in arg loading
988 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -0700989 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700990 }
buzbee2a475e72011-09-07 17:19:17 -0700991#ifdef DISPLAY_MISSING_TARGETS
992 genShowTarget(cUnit);
993#endif
buzbee67bf8852011-08-17 17:51:35 -0700994 newLIR1(cUnit, kThumbBlxR, rLR);
995}
996
997static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
998{
999 DecodedInstruction* dInsn = &mir->dalvikInsn;
1000 int callState = 0;
1001 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -07001002 ArmLIR* rollback;
1003 Method* method = cUnit->method->GetDexCacheResolvedMethods()->
1004 Get(dInsn->vB);
1005 NextCallInsn nextCallInsn;
buzbee7b1b86d2011-08-26 18:59:10 -07001006
buzbee109bd6a2011-09-06 13:58:41 -07001007 // Explicit register usage
1008 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001009 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001010 // Slow path
1011 nextCallInsn = nextVCallInsnSP;
1012 // If we need a slow-path callout, we'll restart here
1013 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1014 rollback->defMask = -1;
1015 } else {
1016 // Fast path
1017 nextCallInsn = nextVCallInsn;
1018 rollback = NULL;
1019 }
buzbee67bf8852011-08-17 17:51:35 -07001020 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
1021 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001022 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001023 else
1024 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001025 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001026 // Finish up any of the call sequence not interleaved in arg loading
1027 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001028 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001029 }
buzbee2a475e72011-09-07 17:19:17 -07001030#ifdef DISPLAY_MISSING_TARGETS
1031 genShowTarget(cUnit);
1032#endif
buzbee67bf8852011-08-17 17:51:35 -07001033 newLIR1(cUnit, kThumbBlxR, rLR);
1034}
1035
buzbee67bf8852011-08-17 17:51:35 -07001036static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
1037 BasicBlock* bb, ArmLIR* labelList)
1038{
1039 bool res = false; // Assume success
1040 RegLocation rlSrc[3];
1041 RegLocation rlDest = badLoc;
1042 RegLocation rlResult = badLoc;
1043 Opcode opcode = mir->dalvikInsn.opcode;
1044
1045 /* Prep Src and Dest locations */
1046 int nextSreg = 0;
1047 int nextLoc = 0;
1048 int attrs = oatDataFlowAttributes[opcode];
1049 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1050 if (attrs & DF_UA) {
1051 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1052 nextSreg++;
1053 } else if (attrs & DF_UA_WIDE) {
1054 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1055 nextSreg + 1);
1056 nextSreg+= 2;
1057 }
1058 if (attrs & DF_UB) {
1059 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1060 nextSreg++;
1061 } else if (attrs & DF_UB_WIDE) {
1062 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1063 nextSreg + 1);
1064 nextSreg+= 2;
1065 }
1066 if (attrs & DF_UC) {
1067 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1068 } else if (attrs & DF_UC_WIDE) {
1069 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1070 nextSreg + 1);
1071 }
1072 if (attrs & DF_DA) {
1073 rlDest = oatGetDest(cUnit, mir, 0);
1074 } else if (attrs & DF_DA_WIDE) {
1075 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1076 }
1077
1078 switch(opcode) {
1079 case OP_NOP:
1080 break;
1081
1082 case OP_MOVE_EXCEPTION:
1083 int exOffset;
1084 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001085 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001086 resetReg = oatAllocTemp(cUnit);
1087 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1088 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1089 loadConstant(cUnit, resetReg, 0);
1090 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1091 storeValue(cUnit, rlDest, rlResult);
1092 break;
1093
1094 case OP_RETURN_VOID:
1095 break;
1096
1097 case OP_RETURN:
1098 case OP_RETURN_OBJECT:
1099 storeValue(cUnit, retLoc, rlSrc[0]);
1100 break;
1101
1102 case OP_RETURN_WIDE:
1103 rlDest = retLocWide;
1104 rlDest.fp = rlSrc[0].fp;
1105 storeValueWide(cUnit, rlDest, rlSrc[0]);
1106 break;
1107
1108 case OP_MOVE_RESULT_WIDE:
1109 if (mir->OptimizationFlags & MIR_INLINED)
1110 break; // Nop - combined w/ previous invoke
1111 /*
1112 * Somewhat hacky here. Because we're now passing
1113 * return values in registers, we have to let the
1114 * register allocation utilities know that the return
1115 * registers are live and may not be used for address
1116 * formation in storeValueWide.
1117 */
1118 assert(retLocWide.lowReg == r0);
buzbee1da522d2011-09-04 11:22:20 -07001119 assert(retLocWide.highReg == r1);
buzbee67bf8852011-08-17 17:51:35 -07001120 oatLockTemp(cUnit, retLocWide.lowReg);
1121 oatLockTemp(cUnit, retLocWide.highReg);
1122 storeValueWide(cUnit, rlDest, retLocWide);
1123 oatFreeTemp(cUnit, retLocWide.lowReg);
1124 oatFreeTemp(cUnit, retLocWide.highReg);
1125 break;
1126
1127 case OP_MOVE_RESULT:
1128 case OP_MOVE_RESULT_OBJECT:
1129 if (mir->OptimizationFlags & MIR_INLINED)
1130 break; // Nop - combined w/ previous invoke
1131 /* See comment for OP_MOVE_RESULT_WIDE */
1132 assert(retLoc.lowReg == r0);
1133 oatLockTemp(cUnit, retLoc.lowReg);
1134 storeValue(cUnit, rlDest, retLoc);
1135 oatFreeTemp(cUnit, retLoc.lowReg);
1136 break;
1137
1138 case OP_MOVE:
1139 case OP_MOVE_OBJECT:
1140 case OP_MOVE_16:
1141 case OP_MOVE_OBJECT_16:
1142 case OP_MOVE_FROM16:
1143 case OP_MOVE_OBJECT_FROM16:
1144 storeValue(cUnit, rlDest, rlSrc[0]);
1145 break;
1146
1147 case OP_MOVE_WIDE:
1148 case OP_MOVE_WIDE_16:
1149 case OP_MOVE_WIDE_FROM16:
1150 storeValueWide(cUnit, rlDest, rlSrc[0]);
1151 break;
1152
1153 case OP_CONST:
1154 case OP_CONST_4:
1155 case OP_CONST_16:
1156 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1157 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1158 storeValue(cUnit, rlDest, rlResult);
1159 break;
1160
1161 case OP_CONST_HIGH16:
1162 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1163 loadConstantNoClobber(cUnit, rlResult.lowReg,
1164 mir->dalvikInsn.vB << 16);
1165 storeValue(cUnit, rlDest, rlResult);
1166 break;
1167
1168 case OP_CONST_WIDE_16:
1169 case OP_CONST_WIDE_32:
1170 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1171 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1172 //TUNING: do high separately to avoid load dependency
1173 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
1174 storeValueWide(cUnit, rlDest, rlResult);
1175 break;
1176
1177 case OP_CONST_WIDE:
1178 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1179 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001180 mir->dalvikInsn.vB_wide & 0xffffffff,
1181 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001182 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001183 break;
1184
1185 case OP_CONST_WIDE_HIGH16:
1186 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1187 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1188 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001189 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001190 break;
1191
1192 case OP_MONITOR_ENTER:
1193 genMonitorEnter(cUnit, mir, rlSrc[0]);
1194 break;
1195
1196 case OP_MONITOR_EXIT:
1197 genMonitorExit(cUnit, mir, rlSrc[0]);
1198 break;
1199
1200 case OP_CHECK_CAST:
1201 genCheckCast(cUnit, mir, rlSrc[0]);
1202 break;
1203
1204 case OP_INSTANCE_OF:
1205 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1206 break;
1207
1208 case OP_NEW_INSTANCE:
1209 genNewInstance(cUnit, mir, rlDest);
1210 break;
1211
1212 case OP_THROW:
1213 genThrow(cUnit, mir, rlSrc[0]);
1214 break;
1215
1216 case OP_ARRAY_LENGTH:
1217 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001218 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001219 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee67bf8852011-08-17 17:51:35 -07001220 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg,
1221 mir->offset, NULL);
1222 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1223 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1224 rlResult.lowReg);
1225 storeValue(cUnit, rlDest, rlResult);
1226 break;
1227
1228 case OP_CONST_STRING:
1229 case OP_CONST_STRING_JUMBO:
1230 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1231 break;
1232
1233 case OP_CONST_CLASS:
1234 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1235 break;
1236
1237 case OP_FILL_ARRAY_DATA:
1238 genFillArrayData(cUnit, mir, rlSrc[0]);
1239 break;
1240
1241 case OP_FILLED_NEW_ARRAY:
1242 genFilledNewArray(cUnit, mir, false /* not range */);
1243 break;
1244
1245 case OP_FILLED_NEW_ARRAY_RANGE:
1246 genFilledNewArray(cUnit, mir, true /* range */);
1247 break;
1248
1249 case OP_NEW_ARRAY:
1250 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1251 break;
1252
1253 case OP_GOTO:
1254 case OP_GOTO_16:
1255 case OP_GOTO_32:
1256 // TUNING: add MIR flag to disable when unnecessary
1257 bool backwardBranch;
1258 backwardBranch = (bb->taken->startOffset <= mir->offset);
1259 if (backwardBranch) {
1260 genSuspendPoll(cUnit, mir);
1261 }
1262 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1263 break;
1264
1265 case OP_PACKED_SWITCH:
1266 genPackedSwitch(cUnit, mir, rlSrc[0]);
1267 break;
1268
1269 case OP_SPARSE_SWITCH:
1270 genSparseSwitch(cUnit, mir, rlSrc[0]);
1271 break;
1272
1273 case OP_CMPL_FLOAT:
1274 case OP_CMPG_FLOAT:
1275 case OP_CMPL_DOUBLE:
1276 case OP_CMPG_DOUBLE:
1277 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1278 break;
1279
1280 case OP_CMP_LONG:
1281 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1282 break;
1283
1284 case OP_IF_EQ:
1285 case OP_IF_NE:
1286 case OP_IF_LT:
1287 case OP_IF_GE:
1288 case OP_IF_GT:
1289 case OP_IF_LE: {
1290 bool backwardBranch;
1291 ArmConditionCode cond;
1292 backwardBranch = (bb->taken->startOffset <= mir->offset);
1293 if (backwardBranch) {
1294 genSuspendPoll(cUnit, mir);
1295 }
1296 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1297 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1298 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1299 switch(opcode) {
1300 case OP_IF_EQ:
1301 cond = kArmCondEq;
1302 break;
1303 case OP_IF_NE:
1304 cond = kArmCondNe;
1305 break;
1306 case OP_IF_LT:
1307 cond = kArmCondLt;
1308 break;
1309 case OP_IF_GE:
1310 cond = kArmCondGe;
1311 break;
1312 case OP_IF_GT:
1313 cond = kArmCondGt;
1314 break;
1315 case OP_IF_LE:
1316 cond = kArmCondLe;
1317 break;
1318 default:
1319 cond = (ArmConditionCode)0;
1320 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1321 }
1322 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1323 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1324 break;
1325 }
1326
1327 case OP_IF_EQZ:
1328 case OP_IF_NEZ:
1329 case OP_IF_LTZ:
1330 case OP_IF_GEZ:
1331 case OP_IF_GTZ:
1332 case OP_IF_LEZ: {
1333 bool backwardBranch;
1334 ArmConditionCode cond;
1335 backwardBranch = (bb->taken->startOffset <= mir->offset);
1336 if (backwardBranch) {
1337 genSuspendPoll(cUnit, mir);
1338 }
1339 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1340 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1341 switch(opcode) {
1342 case OP_IF_EQZ:
1343 cond = kArmCondEq;
1344 break;
1345 case OP_IF_NEZ:
1346 cond = kArmCondNe;
1347 break;
1348 case OP_IF_LTZ:
1349 cond = kArmCondLt;
1350 break;
1351 case OP_IF_GEZ:
1352 cond = kArmCondGe;
1353 break;
1354 case OP_IF_GTZ:
1355 cond = kArmCondGt;
1356 break;
1357 case OP_IF_LEZ:
1358 cond = kArmCondLe;
1359 break;
1360 default:
1361 cond = (ArmConditionCode)0;
1362 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1363 }
1364 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1365 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1366 break;
1367 }
1368
1369 case OP_AGET_WIDE:
1370 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1371 break;
1372 case OP_AGET:
1373 case OP_AGET_OBJECT:
1374 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1375 break;
1376 case OP_AGET_BOOLEAN:
1377 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1378 rlDest, 0);
1379 break;
1380 case OP_AGET_BYTE:
1381 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1382 break;
1383 case OP_AGET_CHAR:
1384 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1385 rlDest, 1);
1386 break;
1387 case OP_AGET_SHORT:
1388 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1389 break;
1390 case OP_APUT_WIDE:
1391 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1392 break;
1393 case OP_APUT:
1394 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1395 break;
1396 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001397 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001398 break;
1399 case OP_APUT_SHORT:
1400 case OP_APUT_CHAR:
1401 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1402 rlSrc[0], 1);
1403 break;
1404 case OP_APUT_BYTE:
1405 case OP_APUT_BOOLEAN:
1406 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1407 rlSrc[0], 0);
1408 break;
1409
1410 case OP_IGET_WIDE:
1411 case OP_IGET_WIDE_VOLATILE:
1412 genIGetWideX(cUnit, mir, rlDest, rlSrc[0]);
1413 break;
1414
1415 case OP_IGET:
1416 case OP_IGET_VOLATILE:
1417 case OP_IGET_OBJECT:
1418 case OP_IGET_OBJECT_VOLATILE:
1419 genIGetX(cUnit, mir, kWord, rlDest, rlSrc[0]);
1420 break;
1421
1422 case OP_IGET_BOOLEAN:
1423 case OP_IGET_BYTE:
1424 genIGetX(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
1425 break;
1426
1427 case OP_IGET_CHAR:
1428 genIGetX(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
1429 break;
1430
1431 case OP_IGET_SHORT:
1432 genIGetX(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
1433 break;
1434
1435 case OP_IPUT_WIDE:
1436 case OP_IPUT_WIDE_VOLATILE:
1437 genIPutWideX(cUnit, mir, rlSrc[0], rlSrc[1]);
1438 break;
1439
1440 case OP_IPUT_OBJECT:
1441 case OP_IPUT_OBJECT_VOLATILE:
1442 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
1443 break;
1444
1445 case OP_IPUT:
1446 case OP_IPUT_VOLATILE:
1447 genIPutX(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
1448 break;
1449
1450 case OP_IPUT_BOOLEAN:
1451 case OP_IPUT_BYTE:
1452 genIPutX(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
1453 break;
1454
1455 case OP_IPUT_CHAR:
1456 genIPutX(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
1457 break;
1458
1459 case OP_IPUT_SHORT:
1460 genIPutX(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
1461 break;
1462
1463 case OP_SGET:
1464 case OP_SGET_OBJECT:
1465 case OP_SGET_BOOLEAN:
1466 case OP_SGET_BYTE:
1467 case OP_SGET_CHAR:
1468 case OP_SGET_SHORT:
1469 genSget(cUnit, mir, rlResult, rlDest);
1470 break;
1471
1472 case OP_SGET_WIDE:
1473 genSgetWide(cUnit, mir, rlResult, rlDest);
1474 break;
1475
1476 case OP_SPUT:
1477 case OP_SPUT_OBJECT:
1478 case OP_SPUT_BOOLEAN:
1479 case OP_SPUT_BYTE:
1480 case OP_SPUT_CHAR:
1481 case OP_SPUT_SHORT:
1482 genSput(cUnit, mir, rlSrc[0]);
1483 break;
1484
1485 case OP_SPUT_WIDE:
1486 genSputWide(cUnit, mir, rlSrc[0]);
1487 break;
1488
1489 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001490 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1491 true /*range*/);
1492 break;
buzbee67bf8852011-08-17 17:51:35 -07001493 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001494 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1495 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001496 break;
1497
1498 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001499 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1500 false /*range*/);
1501 break;
buzbee67bf8852011-08-17 17:51:35 -07001502 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001503 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1504 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001505 break;
1506
1507 case OP_INVOKE_VIRTUAL:
1508 case OP_INVOKE_VIRTUAL_RANGE:
1509 genInvokeVirtual(cUnit, mir);
1510 break;
1511
1512 case OP_INVOKE_SUPER:
1513 case OP_INVOKE_SUPER_RANGE:
1514 genInvokeSuper(cUnit, mir);
1515 break;
1516
1517 case OP_INVOKE_INTERFACE:
1518 case OP_INVOKE_INTERFACE_RANGE:
1519 genInvokeInterface(cUnit, mir);
1520 break;
1521
1522 case OP_NEG_INT:
1523 case OP_NOT_INT:
1524 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1525 break;
1526
1527 case OP_NEG_LONG:
1528 case OP_NOT_LONG:
1529 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1530 break;
1531
1532 case OP_NEG_FLOAT:
1533 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1534 break;
1535
1536 case OP_NEG_DOUBLE:
1537 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1538 break;
1539
1540 case OP_INT_TO_LONG:
1541 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1542 if (rlSrc[0].location == kLocPhysReg) {
1543 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1544 } else {
1545 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1546 }
1547 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1548 rlResult.lowReg, 31);
1549 storeValueWide(cUnit, rlDest, rlResult);
1550 break;
1551
1552 case OP_LONG_TO_INT:
1553 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1554 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1555 storeValue(cUnit, rlDest, rlSrc[0]);
1556 break;
1557
1558 case OP_INT_TO_BYTE:
1559 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1560 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1561 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1562 storeValue(cUnit, rlDest, rlResult);
1563 break;
1564
1565 case OP_INT_TO_SHORT:
1566 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1567 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1568 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1569 storeValue(cUnit, rlDest, rlResult);
1570 break;
1571
1572 case OP_INT_TO_CHAR:
1573 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1574 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1575 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1576 storeValue(cUnit, rlDest, rlResult);
1577 break;
1578
1579 case OP_INT_TO_FLOAT:
1580 case OP_INT_TO_DOUBLE:
1581 case OP_LONG_TO_FLOAT:
1582 case OP_LONG_TO_DOUBLE:
1583 case OP_FLOAT_TO_INT:
1584 case OP_FLOAT_TO_LONG:
1585 case OP_FLOAT_TO_DOUBLE:
1586 case OP_DOUBLE_TO_INT:
1587 case OP_DOUBLE_TO_LONG:
1588 case OP_DOUBLE_TO_FLOAT:
1589 genConversion(cUnit, mir);
1590 break;
1591
1592 case OP_ADD_INT:
1593 case OP_SUB_INT:
1594 case OP_MUL_INT:
1595 case OP_DIV_INT:
1596 case OP_REM_INT:
1597 case OP_AND_INT:
1598 case OP_OR_INT:
1599 case OP_XOR_INT:
1600 case OP_SHL_INT:
1601 case OP_SHR_INT:
1602 case OP_USHR_INT:
1603 case OP_ADD_INT_2ADDR:
1604 case OP_SUB_INT_2ADDR:
1605 case OP_MUL_INT_2ADDR:
1606 case OP_DIV_INT_2ADDR:
1607 case OP_REM_INT_2ADDR:
1608 case OP_AND_INT_2ADDR:
1609 case OP_OR_INT_2ADDR:
1610 case OP_XOR_INT_2ADDR:
1611 case OP_SHL_INT_2ADDR:
1612 case OP_SHR_INT_2ADDR:
1613 case OP_USHR_INT_2ADDR:
1614 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1615 break;
1616
1617 case OP_ADD_LONG:
1618 case OP_SUB_LONG:
1619 case OP_MUL_LONG:
1620 case OP_DIV_LONG:
1621 case OP_REM_LONG:
1622 case OP_AND_LONG:
1623 case OP_OR_LONG:
1624 case OP_XOR_LONG:
1625 case OP_ADD_LONG_2ADDR:
1626 case OP_SUB_LONG_2ADDR:
1627 case OP_MUL_LONG_2ADDR:
1628 case OP_DIV_LONG_2ADDR:
1629 case OP_REM_LONG_2ADDR:
1630 case OP_AND_LONG_2ADDR:
1631 case OP_OR_LONG_2ADDR:
1632 case OP_XOR_LONG_2ADDR:
1633 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1634 break;
1635
buzbee67bf8852011-08-17 17:51:35 -07001636 case OP_SHL_LONG:
1637 case OP_SHR_LONG:
1638 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001639 case OP_SHL_LONG_2ADDR:
1640 case OP_SHR_LONG_2ADDR:
1641 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001642 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1643 break;
1644
1645 case OP_ADD_FLOAT:
1646 case OP_SUB_FLOAT:
1647 case OP_MUL_FLOAT:
1648 case OP_DIV_FLOAT:
1649 case OP_REM_FLOAT:
1650 case OP_ADD_FLOAT_2ADDR:
1651 case OP_SUB_FLOAT_2ADDR:
1652 case OP_MUL_FLOAT_2ADDR:
1653 case OP_DIV_FLOAT_2ADDR:
1654 case OP_REM_FLOAT_2ADDR:
1655 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1656 break;
1657
1658 case OP_ADD_DOUBLE:
1659 case OP_SUB_DOUBLE:
1660 case OP_MUL_DOUBLE:
1661 case OP_DIV_DOUBLE:
1662 case OP_REM_DOUBLE:
1663 case OP_ADD_DOUBLE_2ADDR:
1664 case OP_SUB_DOUBLE_2ADDR:
1665 case OP_MUL_DOUBLE_2ADDR:
1666 case OP_DIV_DOUBLE_2ADDR:
1667 case OP_REM_DOUBLE_2ADDR:
1668 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1669 break;
1670
1671 case OP_RSUB_INT:
1672 case OP_ADD_INT_LIT16:
1673 case OP_MUL_INT_LIT16:
1674 case OP_DIV_INT_LIT16:
1675 case OP_REM_INT_LIT16:
1676 case OP_AND_INT_LIT16:
1677 case OP_OR_INT_LIT16:
1678 case OP_XOR_INT_LIT16:
1679 case OP_ADD_INT_LIT8:
1680 case OP_RSUB_INT_LIT8:
1681 case OP_MUL_INT_LIT8:
1682 case OP_DIV_INT_LIT8:
1683 case OP_REM_INT_LIT8:
1684 case OP_AND_INT_LIT8:
1685 case OP_OR_INT_LIT8:
1686 case OP_XOR_INT_LIT8:
1687 case OP_SHL_INT_LIT8:
1688 case OP_SHR_INT_LIT8:
1689 case OP_USHR_INT_LIT8:
1690 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1691 break;
1692
1693 default:
1694 res = true;
1695 }
1696 return res;
1697}
1698
1699static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1700 "kMirOpPhi",
1701 "kMirOpNullNRangeUpCheck",
1702 "kMirOpNullNRangeDownCheck",
1703 "kMirOpLowerBound",
1704 "kMirOpPunt",
1705 "kMirOpCheckInlinePrediction",
1706};
1707
1708/* Extended MIR instructions like PHI */
1709static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1710{
1711 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1712 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1713 strcpy(msg, extendedMIROpNames[opOffset]);
1714 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1715
1716 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1717 case kMirOpPhi: {
1718 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1719 op->flags.isNop = true;
1720 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1721 break;
1722 }
1723 default:
1724 break;
1725 }
1726}
1727
1728/* If there are any ins passed in registers that have not been promoted
1729 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001730 * Note: at this pointCopy any ins that are passed in register to their
1731 * home location */
buzbee67bf8852011-08-17 17:51:35 -07001732static void flushIns(CompilationUnit* cUnit)
1733{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001734 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001735 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001736 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1737 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001738 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001739 int startLoc = cUnit->method->NumRegisters() -
1740 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001741 for (int i = 0; i < inRegs; i++) {
1742 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001743 //TUNING: be smarter about flushing ins to frame
1744 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001745 if (loc.location == kLocPhysReg) {
1746 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001747 }
1748 }
1749
1750 // Handle special case of wide argument half in regs, half in frame
1751 if (inRegs == 3) {
1752 RegLocation loc = cUnit->regLocation[startLoc + 2];
1753 if (loc.wide && loc.location == kLocPhysReg) {
1754 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001755 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001756 inRegs++;
1757 }
1758 }
1759
1760 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001761 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001762 RegLocation loc = cUnit->regLocation[startLoc + i];
1763 if (loc.fpLocation == kLocPhysReg) {
1764 loc.location = kLocPhysReg;
1765 loc.fp = true;
1766 loc.lowReg = loc.fpLowReg;
1767 loc.highReg = loc.fpHighReg;
1768 }
1769 if (loc.location == kLocPhysReg) {
1770 if (loc.wide) {
1771 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1772 loc.lowReg, loc.highReg, INVALID_SREG);
1773 i++;
1774 } else {
buzbee561227c2011-09-02 15:28:19 -07001775 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001776 }
1777 }
1778 i++;
1779 }
1780}
1781
1782/* Handle the content in each basic block */
1783static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1784{
1785 MIR* mir;
1786 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1787 int blockId = bb->id;
1788
1789 cUnit->curBlock = bb;
1790 labelList[blockId].operands[0] = bb->startOffset;
1791
1792 /* Insert the block label */
1793 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1794 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1795
1796 oatClobberAllRegs(cUnit);
1797 oatResetNullCheck(cUnit);
1798
1799 ArmLIR* headLIR = NULL;
1800
1801 if (bb->blockType == kEntryBlock) {
1802 /*
1803 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1804 * mechanism know so it doesn't try to use any of them when
1805 * expanding the frame or flushing. This leaves the utility
1806 * code with a single temp: r12. This should be enough.
1807 */
1808 oatLockTemp(cUnit, r0);
1809 oatLockTemp(cUnit, r1);
1810 oatLockTemp(cUnit, r2);
1811 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001812
1813 /*
1814 * We can safely skip the stack overflow check if we're
1815 * a leaf *and* our frame size < fudge factor.
1816 */
1817 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1818 ((size_t)cUnit->frameSize <
1819 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001820 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001821 if (!skipOverflowCheck) {
1822 /* Load stack limit */
1823 loadWordDisp(cUnit, rSELF,
1824 art::Thread::StackEndOffset().Int32Value(), r12);
1825 }
buzbee67bf8852011-08-17 17:51:35 -07001826 /* Spill core callee saves */
1827 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1828 /* Need to spill any FP regs? */
1829 if (cUnit->numFPSpills) {
1830 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1831 }
buzbeecefd1872011-09-09 09:59:52 -07001832 if (!skipOverflowCheck) {
1833 opRegRegImm(cUnit, kOpSub, rLR, rSP,
1834 cUnit->frameSize - (cUnit->numSpills * 4));
1835 opRegReg(cUnit, kOpCmp, rLR, r12); // Stack overflow?
1836 /* Begin conditional skip */
1837 genIT(cUnit, kArmCondCc, "TT"); // Carry clear; unsigned <
1838 loadWordDisp(cUnit, rSELF,
1839 OFFSETOF_MEMBER(Thread, pStackOverflowFromCode), rLR);
1840 newLIR2(cUnit, kThumbAddRI8, rSP, cUnit->numSpills * 4);
1841 opReg(cUnit, kOpBlx, rLR);
1842 /* End conditional skip */
1843 genRegCopy(cUnit, rSP, rLR); // Establish stack
1844 } else {
1845 opRegImm(cUnit, kOpSub, rSP,
1846 cUnit->frameSize - (cUnit->numSpills * 4));
1847 }
buzbee67bf8852011-08-17 17:51:35 -07001848 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1849 flushIns(cUnit);
1850 oatFreeTemp(cUnit, r0);
1851 oatFreeTemp(cUnit, r1);
1852 oatFreeTemp(cUnit, r2);
1853 oatFreeTemp(cUnit, r3);
1854 } else if (bb->blockType == kExitBlock) {
1855 newLIR0(cUnit, kArmPseudoMethodExit);
1856 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1857 /* Need to restore any FP callee saves? */
1858 if (cUnit->numFPSpills) {
1859 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1860 }
1861 if (cUnit->coreSpillMask & (1 << rLR)) {
1862 /* Unspill rLR to rPC */
1863 cUnit->coreSpillMask &= ~(1 << rLR);
1864 cUnit->coreSpillMask |= (1 << rPC);
1865 }
1866 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1867 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1868 /* We didn't pop to rPC, so must do a bv rLR */
1869 newLIR1(cUnit, kThumbBx, rLR);
1870 }
1871 }
1872
1873 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1874
1875 oatResetRegPool(cUnit);
1876 if (cUnit->disableOpt & (1 << kTrackLiveTemps)) {
1877 oatClobberAllRegs(cUnit);
1878 }
1879
1880 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1881 oatResetDefTracking(cUnit);
1882 }
1883
1884 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1885 handleExtendedMethodMIR(cUnit, mir);
1886 continue;
1887 }
1888
1889 cUnit->currentDalvikOffset = mir->offset;
1890
1891 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1892 InstructionFormat dalvikFormat =
1893 dexGetFormatFromOpcode(dalvikOpcode);
1894
1895 ArmLIR* boundaryLIR;
1896
1897 /* Mark the beginning of a Dalvik instruction for line tracking */
1898 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1899 (int) oatGetDalvikDisassembly(
1900 &mir->dalvikInsn, ""));
1901 /* Remember the first LIR for this block */
1902 if (headLIR == NULL) {
1903 headLIR = boundaryLIR;
1904 /* Set the first boundaryLIR as a scheduling barrier */
1905 headLIR->defMask = ENCODE_ALL;
1906 }
1907
1908 /* Don't generate the SSA annotation unless verbose mode is on */
1909 if (cUnit->printMe && mir->ssaRep) {
1910 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1911 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1912 }
1913
1914 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1915
1916 if (notHandled) {
1917 char buf[100];
1918 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1919 mir->offset,
1920 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1921 dalvikFormat);
1922 LOG(FATAL) << buf;
1923 }
1924 }
1925
1926 if (headLIR) {
1927 /*
1928 * Eliminate redundant loads/stores and delay stores into later
1929 * slots
1930 */
1931 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1932 cUnit->lastLIRInsn);
1933
1934 /*
1935 * Generate an unconditional branch to the fallthrough block.
1936 */
1937 if (bb->fallThrough) {
1938 genUnconditionalBranch(cUnit,
1939 &labelList[bb->fallThrough->id]);
1940 }
1941 }
1942 return false;
1943}
1944
1945/*
1946 * Nop any unconditional branches that go to the next instruction.
1947 * Note: new redundant branches may be inserted later, and we'll
1948 * use a check in final instruction assembly to nop those out.
1949 */
1950void removeRedundantBranches(CompilationUnit* cUnit)
1951{
1952 ArmLIR* thisLIR;
1953
1954 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1955 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1956 thisLIR = NEXT_LIR(thisLIR)) {
1957
1958 /* Branch to the next instruction */
1959 if ((thisLIR->opcode == kThumbBUncond) ||
1960 (thisLIR->opcode == kThumb2BUncond)) {
1961 ArmLIR* nextLIR = thisLIR;
1962
1963 while (true) {
1964 nextLIR = NEXT_LIR(nextLIR);
1965
1966 /*
1967 * Is the branch target the next instruction?
1968 */
1969 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1970 thisLIR->flags.isNop = true;
1971 break;
1972 }
1973
1974 /*
1975 * Found real useful stuff between the branch and the target.
1976 * Need to explicitly check the lastLIRInsn here because it
1977 * might be the last real instruction.
1978 */
1979 if (!isPseudoOpcode(nextLIR->opcode) ||
1980 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1981 break;
1982 }
1983 }
1984 }
1985}
1986
1987void oatMethodMIR2LIR(CompilationUnit* cUnit)
1988{
1989 /* Used to hold the labels of each block */
1990 cUnit->blockLabelList =
1991 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
1992
1993 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
1994 kPreOrderDFSTraversal, false /* Iterative */);
1995 removeRedundantBranches(cUnit);
1996}
1997
1998/* Common initialization routine for an architecture family */
1999bool oatArchInit()
2000{
2001 int i;
2002
2003 for (i = 0; i < kArmLast; i++) {
2004 if (EncodingMap[i].opcode != i) {
2005 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2006 " is wrong: expecting " << i << ", seeing " <<
2007 (int)EncodingMap[i].opcode;
2008 }
2009 }
2010
2011 return oatArchVariantInit();
2012}
2013
2014/* Needed by the Assembler */
2015void oatSetupResourceMasks(ArmLIR* lir)
2016{
2017 setupResourceMasks(lir);
2018}
2019
2020/* Needed by the ld/st optmizatons */
2021ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2022{
2023 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2024}
2025
2026/* Needed by the register allocator */
2027ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2028{
2029 return genRegCopy(cUnit, rDest, rSrc);
2030}
2031
2032/* Needed by the register allocator */
2033void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2034 int srcLo, int srcHi)
2035{
2036 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2037}
2038
2039void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2040 int displacement, int rSrc, OpSize size)
2041{
2042 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2043}
2044
2045void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2046 int displacement, int rSrcLo, int rSrcHi)
2047{
2048 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2049}