blob: 595bc986b534138da0e39c67e54b1a558c2f1e28 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughes1240dad2011-09-09 16:24:50 -070017#define DISPLAY_MISSING_TARGETS 1
18
buzbee67bf8852011-08-17 17:51:35 -070019static const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
20 INVALID_REG, INVALID_SREG, 0,
21 kLocDalvikFrame, INVALID_REG, INVALID_REG,
22 INVALID_OFFSET};
23static const RegLocation retLoc = LOC_DALVIK_RETURN_VAL;
24static const RegLocation retLocWide = LOC_DALVIK_RETURN_VAL_WIDE;
25
buzbeedfd3d702011-08-28 12:56:51 -070026/*
27 * Let helper function take care of everything. Will call
28 * Array::AllocFromCode(type_idx, method, count);
29 * Note: AllocFromCode will handle checks for errNegativeArraySize.
30 */
buzbee67bf8852011-08-17 17:51:35 -070031static void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
32 RegLocation rlSrc)
33{
buzbeedfd3d702011-08-28 12:56:51 -070034 oatFlushAllRegs(cUnit); /* Everything to home location */
35 loadWordDisp(cUnit, rSELF,
36 OFFSETOF_MEMBER(Thread, pAllocFromCode), rLR);
37 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
38 loadConstant(cUnit, r0, mir->dalvikInsn.vC); // arg0 <- type_id
39 loadValueDirectFixed(cUnit, rlSrc, r2); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070040 callRuntimeHelper(cUnit, rLR);
buzbeedfd3d702011-08-28 12:56:51 -070041 oatClobberCallRegs(cUnit);
42 RegLocation rlResult = oatGetReturn(cUnit);
43 storeValue(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -070044}
45
46/*
47 * Similar to genNewArray, but with post-allocation initialization.
48 * Verifier guarantees we're dealing with an array class. Current
49 * code throws runtime exception "bad Filled array req" for 'D' and 'J'.
50 * Current code also throws internal unimp if not 'L', '[' or 'I'.
51 */
52static void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange)
53{
54 DecodedInstruction* dInsn = &mir->dalvikInsn;
buzbee81eccc02011-09-17 13:42:21 -070055 int elems = dInsn->vA;
56 int typeId = dInsn->vB;
buzbeedfd3d702011-08-28 12:56:51 -070057 oatFlushAllRegs(cUnit); /* Everything to home location */
buzbeedfd3d702011-08-28 12:56:51 -070058 loadWordDisp(cUnit, rSELF,
buzbee1da522d2011-09-04 11:22:20 -070059 OFFSETOF_MEMBER(Thread, pCheckAndAllocFromCode), rLR);
buzbeedfd3d702011-08-28 12:56:51 -070060 loadCurrMethodDirect(cUnit, r1); // arg1 <- Method*
61 loadConstant(cUnit, r0, typeId); // arg0 <- type_id
62 loadConstant(cUnit, r2, elems); // arg2 <- count
Ian Rogersff1ed472011-09-20 13:46:24 -070063 callRuntimeHelper(cUnit, rLR);
buzbee67bf8852011-08-17 17:51:35 -070064 /*
buzbeedfd3d702011-08-28 12:56:51 -070065 * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
66 * return region. Because AllocFromCode placed the new array
67 * in r0, we'll just lock it into place. When debugger support is
68 * added, it may be necessary to additionally copy all return
69 * values to a home location in thread-local storage
buzbee67bf8852011-08-17 17:51:35 -070070 */
buzbee67bf8852011-08-17 17:51:35 -070071 oatLockTemp(cUnit, r0);
buzbeedfd3d702011-08-28 12:56:51 -070072
buzbee67bf8852011-08-17 17:51:35 -070073 // Having a range of 0 is legal
74 if (isRange && (dInsn->vA > 0)) {
75 /*
76 * Bit of ugliness here. We're going generate a mem copy loop
77 * on the register range, but it is possible that some regs
78 * in the range have been promoted. This is unlikely, but
79 * before generating the copy, we'll just force a flush
80 * of any regs in the source range that have been promoted to
81 * home location.
82 */
83 for (unsigned int i = 0; i < dInsn->vA; i++) {
84 RegLocation loc = oatUpdateLoc(cUnit,
85 oatGetSrc(cUnit, mir, i));
86 if (loc.location == kLocPhysReg) {
87 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
88 }
89 }
90 /*
91 * TUNING note: generated code here could be much improved, but
92 * this is an uncommon operation and isn't especially performance
93 * critical.
94 */
95 int rSrc = oatAllocTemp(cUnit);
96 int rDst = oatAllocTemp(cUnit);
97 int rIdx = oatAllocTemp(cUnit);
98 int rVal = rLR; // Using a lot of temps, rLR is known free here
99 // Set up source pointer
100 RegLocation rlFirst = oatGetSrc(cUnit, mir, 0);
101 opRegRegImm(cUnit, kOpAdd, rSrc, rSP, rlFirst.spOffset);
102 // Set up the target pointer
103 opRegRegImm(cUnit, kOpAdd, rDst, r0,
buzbeec143c552011-08-20 17:38:58 -0700104 Array::DataOffset().Int32Value());
buzbee67bf8852011-08-17 17:51:35 -0700105 // Set up the loop counter (known to be > 0)
106 loadConstant(cUnit, rIdx, dInsn->vA);
107 // Generate the copy loop. Going backwards for convenience
108 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
109 target->defMask = ENCODE_ALL;
110 // Copy next element
111 loadBaseIndexed(cUnit, rSrc, rIdx, rVal, 2, kWord);
112 storeBaseIndexed(cUnit, rDst, rIdx, rVal, 2, kWord);
113 // Use setflags encoding here
114 newLIR3(cUnit, kThumb2SubsRRI12, rIdx, rIdx, 1);
115 ArmLIR* branch = opCondBranch(cUnit, kArmCondNe);
116 branch->generic.target = (LIR*)target;
117 } else if (!isRange) {
118 // TUNING: interleave
119 for (unsigned int i = 0; i < dInsn->vA; i++) {
120 RegLocation rlArg = loadValue(cUnit,
121 oatGetSrc(cUnit, mir, i), kCoreReg);
buzbeec143c552011-08-20 17:38:58 -0700122 storeBaseDisp(cUnit, r0,
123 Array::DataOffset().Int32Value() +
buzbee67bf8852011-08-17 17:51:35 -0700124 i * 4, rlArg.lowReg, kWord);
125 // If the loadValue caused a temp to be allocated, free it
126 if (oatIsTemp(cUnit, rlArg.lowReg)) {
127 oatFreeTemp(cUnit, rlArg.lowReg);
128 }
129 }
130 }
131}
132
Brian Carlstrom845490b2011-09-19 15:56:53 -0700133Field* FindFieldWithResolvedStaticStorage(const Method* method,
134 const uint32_t fieldIdx,
135 uint32_t& resolvedTypeIdx) {
136 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
137 Field* field = class_linker->ResolveField(fieldIdx, method, true);
138 if (field == NULL) {
139 return NULL;
140 }
141 const art::DexFile& dex_file = class_linker->
142 FindDexFile(method->GetDeclaringClass()->GetDexCache());
143 const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
144 int type_idx = field_id.class_idx_;
145 Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
146 // Check if storage class is the same as class referred to by type idx.
147 // They may not be if the FieldId refers a subclass, but storage is in super
148 if (field->GetDeclaringClass() == klass) {
149 resolvedTypeIdx = type_idx;
150 return field;
151 }
152 // See if we can find a dex reference for the storage class.
153 // we may not if the dex file never references the super class,
154 // but usually it will.
155 std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
156 for (size_t type_idx = 0; type_idx < dex_file.NumTypeIds(); type_idx++) {
157 const art::DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
158 if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
159 resolvedTypeIdx = type_idx;
160 return field;
161 }
162 }
163 return NULL; // resort to slow path
164}
165
buzbee67bf8852011-08-17 17:51:35 -0700166static void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
167{
buzbeee1931742011-08-28 21:15:53 -0700168 bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
169 (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
buzbee1da522d2011-09-04 11:22:20 -0700170 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700171 uint32_t typeIdx;
172 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
173 if (SLOW_FIELD_PATH || field == NULL) {
buzbee1da522d2011-09-04 11:22:20 -0700174 // Slow path
buzbee34cd9e52011-09-08 14:31:52 -0700175 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
176 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700177 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
178 : OFFSETOF_MEMBER(Thread, pSet32Static);
buzbeee1931742011-08-28 21:15:53 -0700179 oatFlushAllRegs(cUnit);
180 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
181 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
182 loadCurrMethodDirect(cUnit, r1);
183 loadValueDirect(cUnit, rlSrc, r2);
Ian Rogersff1ed472011-09-20 13:46:24 -0700184 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700185 oatClobberCallRegs(cUnit);
186 } else {
buzbee1da522d2011-09-04 11:22:20 -0700187 // fast path
188 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700189 // Using fixed register to sync with slow path
190 int rMethod = r1;
191 oatLockTemp(cUnit, rMethod);
192 loadCurrMethodDirect(cUnit, rMethod);
193 int rBase = r0;
194 oatLockTemp(cUnit, rBase);
195 loadWordDisp(cUnit, rMethod,
196 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
197 rBase);
198 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
199 sizeof(int32_t*)* typeIdx, rBase);
200 // TUNING: fast path should fall through
201 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
202 loadWordDisp(cUnit, rSELF,
203 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
204 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700205 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700206 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
207 skipTarget->defMask = ENCODE_ALL;
208 branchOver->generic.target = (LIR*)skipTarget;
209 rlSrc = oatGetSrc(cUnit, mir, 0);
210 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
211 storeWordDisp(cUnit, rBase, fieldOffset, rlSrc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -0700212#if ANDROID_SMP != 0
buzbee1da522d2011-09-04 11:22:20 -0700213 if (field->IsVolatile()) {
214 oatGenMemBarrier(cUnit, kSY);
215 }
buzbee67bf8852011-08-17 17:51:35 -0700216#endif
buzbee1da522d2011-09-04 11:22:20 -0700217 if (isObject) {
218 markGCCard(cUnit, rlSrc.lowReg, rBase);
219 }
220 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700221 }
buzbee67bf8852011-08-17 17:51:35 -0700222}
223
224static void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
225{
buzbee1da522d2011-09-04 11:22:20 -0700226 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700227 uint32_t typeIdx;
228 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700229 if (SLOW_FIELD_PATH || field == NULL) {
230 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
231 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700232 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700233 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700234 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
235 loadCurrMethodDirect(cUnit, r1);
236 loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
Ian Rogersff1ed472011-09-20 13:46:24 -0700237 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700238 oatClobberCallRegs(cUnit);
239 } else {
buzbee1da522d2011-09-04 11:22:20 -0700240 // fast path
241 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700242 // Using fixed register to sync with slow path
243 int rMethod = r1;
244 oatLockTemp(cUnit, rMethod);
245 loadCurrMethodDirect(cUnit, r1);
246 int rBase = r0;
247 oatLockTemp(cUnit, rBase);
248 loadWordDisp(cUnit, rMethod,
249 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
250 rBase);
251 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
252 sizeof(int32_t*)* typeIdx, rBase);
253 // TUNING: fast path should fall through
254 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
255 loadWordDisp(cUnit, rSELF,
256 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
257 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700258 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700259 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
260 skipTarget->defMask = ENCODE_ALL;
261 branchOver->generic.target = (LIR*)skipTarget;
262 rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
263 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
264 storeBaseDispWide(cUnit, rBase, fieldOffset, rlSrc.lowReg,
265 rlSrc.highReg);
266#if ANDROID_SMP != 0
267 if (field->IsVolatile()) {
268 oatGenMemBarrier(cUnit, kSY);
269 }
buzbeec143c552011-08-20 17:38:58 -0700270#endif
buzbee1da522d2011-09-04 11:22:20 -0700271 oatFreeTemp(cUnit, rBase);
buzbeee1931742011-08-28 21:15:53 -0700272 }
buzbee67bf8852011-08-17 17:51:35 -0700273}
274
275
buzbee67bf8852011-08-17 17:51:35 -0700276static void genSgetWide(CompilationUnit* cUnit, MIR* mir,
277 RegLocation rlResult, RegLocation rlDest)
278{
buzbee1da522d2011-09-04 11:22:20 -0700279 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700280 uint32_t typeIdx;
281 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbee34cd9e52011-09-08 14:31:52 -0700282 if (SLOW_FIELD_PATH || field == NULL) {
283 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
284 << " unresolved at compile time";
buzbeee1931742011-08-28 21:15:53 -0700285 oatFlushAllRegs(cUnit);
buzbee1da522d2011-09-04 11:22:20 -0700286 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
buzbeee1931742011-08-28 21:15:53 -0700287 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
288 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700289 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700290 RegLocation rlResult = oatGetReturnWide(cUnit);
291 storeValueWide(cUnit, rlDest, rlResult);
292 } else {
buzbee1da522d2011-09-04 11:22:20 -0700293 // Fast path
294 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700295 // Using fixed register to sync with slow path
296 int rMethod = r1;
297 oatLockTemp(cUnit, rMethod);
298 loadCurrMethodDirect(cUnit, rMethod);
299 int rBase = r0;
300 oatLockTemp(cUnit, rBase);
301 loadWordDisp(cUnit, rMethod,
302 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
303 rBase);
304 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
305 sizeof(int32_t*)* typeIdx, rBase);
306 // TUNING: fast path should fall through
307 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
308 loadWordDisp(cUnit, rSELF,
309 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
310 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700311 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700312 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
313 skipTarget->defMask = ENCODE_ALL;
314 branchOver->generic.target = (LIR*)skipTarget;
315 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
316 RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
317#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700318 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700319 oatGenMemBarrier(cUnit, kSY);
320 }
buzbeec143c552011-08-20 17:38:58 -0700321#endif
buzbee1da522d2011-09-04 11:22:20 -0700322 loadBaseDispWide(cUnit, NULL, rBase, fieldOffset, rlResult.lowReg,
323 rlResult.highReg, INVALID_SREG);
324 oatFreeTemp(cUnit, rBase);
325 storeValueWide(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700326 }
buzbee67bf8852011-08-17 17:51:35 -0700327}
328
329static void genSget(CompilationUnit* cUnit, MIR* mir,
330 RegLocation rlResult, RegLocation rlDest)
331{
buzbee1da522d2011-09-04 11:22:20 -0700332 int fieldIdx = mir->dalvikInsn.vB;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700333 uint32_t typeIdx;
334 Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
buzbeee1931742011-08-28 21:15:53 -0700335 bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
336 (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
buzbee34cd9e52011-09-08 14:31:52 -0700337 if (SLOW_FIELD_PATH || field == NULL) {
338 LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
339 << " unresolved at compile time";
buzbee1da522d2011-09-04 11:22:20 -0700340 // Slow path
341 int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
342 : OFFSETOF_MEMBER(Thread, pGet32Static);
buzbeee1931742011-08-28 21:15:53 -0700343 oatFlushAllRegs(cUnit);
344 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
345 loadConstant(cUnit, r0, mir->dalvikInsn.vB);
346 loadCurrMethodDirect(cUnit, r1);
Ian Rogersff1ed472011-09-20 13:46:24 -0700347 callRuntimeHelper(cUnit, rLR);
buzbeee1931742011-08-28 21:15:53 -0700348 RegLocation rlResult = oatGetReturn(cUnit);
349 storeValue(cUnit, rlDest, rlResult);
350 } else {
buzbee1da522d2011-09-04 11:22:20 -0700351 // Fast path
352 int fieldOffset = field->GetOffset().Int32Value();
buzbee1da522d2011-09-04 11:22:20 -0700353 // Using fixed register to sync with slow path
354 int rMethod = r1;
355 oatLockTemp(cUnit, rMethod);
356 loadCurrMethodDirect(cUnit, rMethod);
357 int rBase = r0;
358 oatLockTemp(cUnit, rBase);
359 loadWordDisp(cUnit, rMethod,
360 Method::DexCacheInitializedStaticStorageOffset().Int32Value(),
361 rBase);
362 loadWordDisp(cUnit, rBase, art::Array::DataOffset().Int32Value() +
363 sizeof(int32_t*)* typeIdx, rBase);
364 // TUNING: fast path should fall through
365 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rBase, 0);
366 loadWordDisp(cUnit, rSELF,
367 OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
368 loadConstant(cUnit, r0, typeIdx);
Ian Rogersff1ed472011-09-20 13:46:24 -0700369 callRuntimeHelper(cUnit, rLR);
buzbee1da522d2011-09-04 11:22:20 -0700370 ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
371 skipTarget->defMask = ENCODE_ALL;
372 branchOver->generic.target = (LIR*)skipTarget;
373 rlDest = oatGetDest(cUnit, mir, 0);
374 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
buzbee67bf8852011-08-17 17:51:35 -0700375#if ANDROID_SMP != 0
Elliott Hughes1d3f1142011-09-13 12:00:00 -0700376 if (field->IsVolatile()) {
buzbee1da522d2011-09-04 11:22:20 -0700377 oatGenMemBarrier(cUnit, kSY);
378 }
buzbee67bf8852011-08-17 17:51:35 -0700379#endif
buzbee1da522d2011-09-04 11:22:20 -0700380 loadWordDisp(cUnit, rBase, fieldOffset, rlResult.lowReg);
381 oatFreeTemp(cUnit, rBase);
382 storeValue(cUnit, rlDest, rlResult);
buzbeee1931742011-08-28 21:15:53 -0700383 }
buzbee67bf8852011-08-17 17:51:35 -0700384}
385
buzbee561227c2011-09-02 15:28:19 -0700386typedef int (*NextCallInsn)(CompilationUnit*, MIR*, DecodedInstruction*, int,
387 ArmLIR*);
buzbee67bf8852011-08-17 17:51:35 -0700388
389/*
390 * Bit of a hack here - in leiu of a real scheduling pass,
391 * emit the next instruction in static & direct invoke sequences.
392 */
393static int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700394 DecodedInstruction* dInsn, int state,
395 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700396{
buzbee561227c2011-09-02 15:28:19 -0700397 DCHECK(rollback == NULL);
398 uint32_t idx = dInsn->vB;
buzbee67bf8852011-08-17 17:51:35 -0700399 switch(state) {
400 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700401 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700402 break;
buzbee561227c2011-09-02 15:28:19 -0700403 case 1: // Get method->code_and_direct_methods_
404 loadWordDisp(cUnit, r0,
405 Method::GetDexCacheCodeAndDirectMethodsOffset().Int32Value(),
406 r0);
buzbee67bf8852011-08-17 17:51:35 -0700407 break;
buzbee561227c2011-09-02 15:28:19 -0700408 case 2: // Grab target method* and target code_
409 loadWordDisp(cUnit, r0,
410 art::CodeAndDirectMethods::CodeOffsetInBytes(idx), rLR);
411 loadWordDisp(cUnit, r0,
412 art::CodeAndDirectMethods::MethodOffsetInBytes(idx), r0);
buzbeec5ef0462011-08-25 18:44:49 -0700413 break;
414 default:
415 return -1;
416 }
417 return state + 1;
418}
419
buzbee67bf8852011-08-17 17:51:35 -0700420/*
421 * Bit of a hack here - in leiu of a real scheduling pass,
422 * emit the next instruction in a virtual invoke sequence.
423 * We can use rLR as a temp prior to target address loading
424 * Note also that we'll load the first argument ("this") into
425 * r1 here rather than the standard loadArgRegs.
426 */
427static int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700428 DecodedInstruction* dInsn, int state,
429 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700430{
buzbee561227c2011-09-02 15:28:19 -0700431 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700432 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700433 /*
434 * This is the fast path in which the target virtual method is
435 * fully resolved at compile time.
436 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700437 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
438 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -0700439 CHECK(baseMethod != NULL);
440 uint32_t target_idx = baseMethod->GetMethodIndex();
buzbee67bf8852011-08-17 17:51:35 -0700441 switch(state) {
buzbee561227c2011-09-02 15:28:19 -0700442 case 0: // Get "this" [set r1]
buzbee67bf8852011-08-17 17:51:35 -0700443 rlArg = oatGetSrc(cUnit, mir, 0);
444 loadValueDirectFixed(cUnit, rlArg, r1);
445 break;
buzbee561227c2011-09-02 15:28:19 -0700446 case 1: // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700447 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee561227c2011-09-02 15:28:19 -0700448 // get this->klass_ [use r1, set rLR]
449 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700450 break;
buzbee561227c2011-09-02 15:28:19 -0700451 case 2: // Get this->klass_->vtable [usr rLR, set rLR]
452 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700453 break;
buzbee561227c2011-09-02 15:28:19 -0700454 case 3: // Get target method [use rLR, set r0]
455 loadWordDisp(cUnit, rLR, (target_idx * 4) +
456 art::Array::DataOffset().Int32Value(), r0);
457 break;
458 case 4: // Get the target compiled code address [uses r0, sets rLR]
459 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee67bf8852011-08-17 17:51:35 -0700460 break;
461 default:
462 return -1;
463 }
464 return state + 1;
465}
466
buzbee7b1b86d2011-08-26 18:59:10 -0700467static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700468 DecodedInstruction* dInsn, int state,
469 ArmLIR* rollback)
buzbee7b1b86d2011-08-26 18:59:10 -0700470{
buzbee561227c2011-09-02 15:28:19 -0700471 DCHECK(rollback != NULL);
buzbee7b1b86d2011-08-26 18:59:10 -0700472 RegLocation rlArg;
buzbee561227c2011-09-02 15:28:19 -0700473 ArmLIR* skipBranch;
474 ArmLIR* skipTarget;
475 /*
476 * This handles the case in which the base method is not fully
477 * resolved at compile time. We must generate code to test
478 * for resolution a run time, bail to the slow path if not to
479 * fill in all the tables. In the latter case, we'll restart at
480 * at the beginning of the sequence.
481 */
buzbee7b1b86d2011-08-26 18:59:10 -0700482 switch(state) {
483 case 0: // Get the current Method* [sets r0]
buzbeedfd3d702011-08-28 12:56:51 -0700484 loadCurrMethodDirect(cUnit, r0);
buzbee7b1b86d2011-08-26 18:59:10 -0700485 break;
buzbee561227c2011-09-02 15:28:19 -0700486 case 1: // Get method->dex_cache_resolved_methods_
487 loadWordDisp(cUnit, r0,
488 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700489 break;
buzbee561227c2011-09-02 15:28:19 -0700490 case 2: // method->dex_cache_resolved_methods_->Get(method_idx)
491 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
492 art::Array::DataOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700493 break;
buzbee561227c2011-09-02 15:28:19 -0700494 case 3: // Resolved?
495 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
496 // Slowest path, bail to helper, rollback and retry
497 loadWordDisp(cUnit, rSELF,
498 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
499 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700500 callRuntimeHelper(cUnit, rLR);
buzbee561227c2011-09-02 15:28:19 -0700501 genUnconditionalBranch(cUnit, rollback);
502 // Resume normal slow path
503 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
504 skipTarget->defMask = ENCODE_ALL;
505 skipBranch->generic.target = (LIR*)skipTarget;
buzbee4a3164f2011-09-03 11:25:10 -0700506 // Get base_method->method_index [usr rLR, set r0]
buzbee561227c2011-09-02 15:28:19 -0700507 loadBaseDisp(cUnit, mir, rLR,
508 Method::GetMethodIndexOffset().Int32Value(), r0,
509 kUnsignedHalf, INVALID_SREG);
buzbee7b1b86d2011-08-26 18:59:10 -0700510 // Load "this" [set r1]
511 rlArg = oatGetSrc(cUnit, mir, 0);
512 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee7b1b86d2011-08-26 18:59:10 -0700513 break;
514 case 4:
515 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700516 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee7b1b86d2011-08-26 18:59:10 -0700517 // get this->clazz [use r1, set rLR]
buzbee561227c2011-09-02 15:28:19 -0700518 loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700519 break;
buzbee561227c2011-09-02 15:28:19 -0700520 case 5:
521 // get this->klass_->vtable_ [usr rLR, set rLR]
522 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
523 DCHECK((art::Array::DataOffset().Int32Value() & 0x3) == 0);
524 // In load shadow fold vtable_ object header size into method_index_
525 opRegImm(cUnit, kOpAdd, r0,
526 art::Array::DataOffset().Int32Value() / 4);
527 // Get target Method*
528 loadBaseIndexed(cUnit, rLR, r0, r0, 2, kWord);
529 break;
530 case 6: // Get the target compiled code address [uses r0, sets rLR]
531 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
buzbee7b1b86d2011-08-26 18:59:10 -0700532 break;
533 default:
534 return -1;
535 }
536 return state + 1;
537}
538
buzbee67bf8852011-08-17 17:51:35 -0700539/* Load up to 3 arguments in r1..r3 */
540static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
541 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700542 int *args, NextCallInsn nextCallInsn, ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700543{
544 for (int i = 0; i < 3; i++) {
545 if (args[i] != INVALID_REG) {
buzbee1b4c8592011-08-31 10:43:51 -0700546 // Arguments are treated as a series of untyped 32-bit values.
buzbeee9a72f62011-09-04 17:59:07 -0700547 RegLocation rlArg = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700548 rlArg.wide = false;
buzbee67bf8852011-08-17 17:51:35 -0700549 loadValueDirectFixed(cUnit, rlArg, r1 + i);
buzbee561227c2011-09-02 15:28:19 -0700550 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700551 }
552 }
553 return callState;
554}
555
buzbee4a3164f2011-09-03 11:25:10 -0700556// Interleave launch code for INVOKE_INTERFACE.
buzbee67bf8852011-08-17 17:51:35 -0700557static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700558 DecodedInstruction* dInsn, int state,
559 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700560{
buzbee67bf8852011-08-17 17:51:35 -0700561 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700562 case 0: // Load trampoline target
563 loadWordDisp(cUnit, rSELF,
564 OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline),
565 rLR);
566 // Load r0 with method index
567 loadConstant(cUnit, r0, dInsn->vB);
buzbee67bf8852011-08-17 17:51:35 -0700568 break;
buzbee67bf8852011-08-17 17:51:35 -0700569 default:
570 return -1;
571 }
572 return state + 1;
573}
574
buzbee67bf8852011-08-17 17:51:35 -0700575/*
576 * Interleave launch code for INVOKE_SUPER. See comments
577 * for nextVCallIns.
578 */
579static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
buzbee561227c2011-09-02 15:28:19 -0700580 DecodedInstruction* dInsn, int state,
581 ArmLIR* rollback)
buzbee67bf8852011-08-17 17:51:35 -0700582{
buzbee4a3164f2011-09-03 11:25:10 -0700583 DCHECK(rollback == NULL);
buzbee67bf8852011-08-17 17:51:35 -0700584 RegLocation rlArg;
buzbee4a3164f2011-09-03 11:25:10 -0700585 /*
586 * This is the fast path in which the target virtual method is
587 * fully resolved at compile time. Note also that this path assumes
588 * that the check to verify that the target method index falls
589 * within the size of the super's vtable has been done at compile-time.
590 */
Brian Carlstrom845490b2011-09-19 15:56:53 -0700591 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
592 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700593 CHECK(baseMethod != NULL);
594 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
595 CHECK(superClass != NULL);
596 int32_t target_idx = baseMethod->GetMethodIndex();
597 CHECK(superClass->GetVTable()->GetLength() > target_idx);
598 Method* targetMethod = superClass->GetVTable()->Get(target_idx);
599 CHECK(targetMethod != NULL);
buzbee67bf8852011-08-17 17:51:35 -0700600 switch(state) {
buzbee4a3164f2011-09-03 11:25:10 -0700601 case 0: // Get current Method* [set r0]
buzbeedfd3d702011-08-28 12:56:51 -0700602 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700603 // Load "this" [set r1]
604 rlArg = oatGetSrc(cUnit, mir, 0);
605 loadValueDirectFixed(cUnit, rlArg, r1);
buzbee4a3164f2011-09-03 11:25:10 -0700606 // Get method->declaring_class_ [use r0, set rLR]
607 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
608 rLR);
buzbee67bf8852011-08-17 17:51:35 -0700609 // Is "this" null? [use r1]
buzbee5ade1d22011-09-09 14:44:52 -0700610 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee4a3164f2011-09-03 11:25:10 -0700611 break;
612 case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
613 loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
614 rLR);
615 break;
616 case 2: // Get ...->super_class_->vtable [u/s rLR]
617 loadWordDisp(cUnit, rLR, Class::VTableOffset().Int32Value(), rLR);
618 break;
619 case 3: // Get target method [use rLR, set r0]
620 loadWordDisp(cUnit, rLR, (target_idx * 4) +
621 art::Array::DataOffset().Int32Value(), r0);
622 break;
623 case 4: // Get the target compiled code address [uses r0, sets rLR]
624 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
625 break;
buzbee67bf8852011-08-17 17:51:35 -0700626 default:
627 return -1;
628 }
buzbee4a3164f2011-09-03 11:25:10 -0700629 return state + 1;
630}
631
632/* Slow-path version of nextSuperCallInsn */
633static int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir,
634 DecodedInstruction* dInsn, int state,
635 ArmLIR* rollback)
636{
637 DCHECK(rollback != NULL);
638 RegLocation rlArg;
639 ArmLIR* skipBranch;
640 ArmLIR* skipTarget;
641 int tReg;
642 /*
643 * This handles the case in which the base method is not fully
644 * resolved at compile time. We must generate code to test
645 * for resolution a run time, bail to the slow path if not to
646 * fill in all the tables. In the latter case, we'll restart at
647 * at the beginning of the sequence.
648 */
649 switch(state) {
650 case 0: // Get the current Method* [sets r0]
651 loadCurrMethodDirect(cUnit, r0);
652 break;
653 case 1: // Get method->dex_cache_resolved_methods_ [usr r0, set rLR]
654 loadWordDisp(cUnit, r0,
655 Method::GetDexCacheResolvedMethodsOffset().Int32Value(), rLR);
656 break;
657 case 2: // method->dex_cache_resolved_methods_->Get(meth_idx) [u/s rLR]
658 loadWordDisp(cUnit, rLR, (dInsn->vB * 4) +
659 art::Array::DataOffset().Int32Value(), rLR);
660 break;
661 case 3: // Resolved?
662 skipBranch = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
663 // Slowest path, bail to helper, rollback and retry
664 loadWordDisp(cUnit, rSELF,
665 OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
666 loadConstant(cUnit, r1, dInsn->vB);
Ian Rogersff1ed472011-09-20 13:46:24 -0700667 callRuntimeHelper(cUnit, rLR);
buzbee4a3164f2011-09-03 11:25:10 -0700668 genUnconditionalBranch(cUnit, rollback);
669 // Resume normal slow path
670 skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
671 skipTarget->defMask = ENCODE_ALL;
672 skipBranch->generic.target = (LIR*)skipTarget;
673 // Get base_method->method_index [usr rLR, set rLR]
674 loadBaseDisp(cUnit, mir, rLR,
675 Method::GetMethodIndexOffset().Int32Value(), rLR,
676 kUnsignedHalf, INVALID_SREG);
677 // Load "this" [set r1]
678 rlArg = oatGetSrc(cUnit, mir, 0);
679 loadValueDirectFixed(cUnit, rlArg, r1);
680 // Load curMethod->declaring_class_ [uses r0, sets r0]
681 loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
682 r0);
buzbee6a0f7f52011-09-05 16:14:20 -0700683 // Null this?
buzbee5ade1d22011-09-09 14:44:52 -0700684 genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee6a0f7f52011-09-05 16:14:20 -0700685 // Get method->declaring_class_->super_class [usr r0, set r0]
buzbee4a3164f2011-09-03 11:25:10 -0700686 loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
687 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700688 case 4: // Get ...->super_class_->vtable [u/s r0]
buzbee4a3164f2011-09-03 11:25:10 -0700689 loadWordDisp(cUnit, r0, Class::VTableOffset().Int32Value(), r0);
buzbee43a36422011-09-14 14:00:13 -0700690 if (!(mir->optimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
buzbee4a3164f2011-09-03 11:25:10 -0700691 // Range check, throw NSM on failure
692 tReg = oatAllocTemp(cUnit);
693 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
694 tReg);
buzbeeec5adf32011-09-11 15:25:43 -0700695 genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
696 kArmThrowNoSuchMethod);
buzbee4a3164f2011-09-03 11:25:10 -0700697 oatFreeTemp(cUnit, tReg);
698 }
buzbee6a0f7f52011-09-05 16:14:20 -0700699 // Adjust vtable_ base past object header
700 opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
buzbee4a3164f2011-09-03 11:25:10 -0700701 // Get target Method*
buzbee6a0f7f52011-09-05 16:14:20 -0700702 loadBaseIndexed(cUnit, r0, rLR, r0, 2, kWord);
buzbee4a3164f2011-09-03 11:25:10 -0700703 break;
buzbee6a0f7f52011-09-05 16:14:20 -0700704 case 5: // Get the target compiled code address [uses r0, sets rLR]
buzbee4a3164f2011-09-03 11:25:10 -0700705 loadWordDisp(cUnit, r0, Method::GetCodeOffset().Int32Value(), rLR);
706 break;
707 default:
708 return -1;
709 }
buzbee67bf8852011-08-17 17:51:35 -0700710 return state + 1;
711}
712
713/*
714 * Load up to 5 arguments, the first three of which will be in
715 * r1 .. r3. On entry r0 contains the current method pointer,
716 * and as part of the load sequence, it must be replaced with
717 * the target method pointer. Note, this may also be called
718 * for "range" variants if the number of arguments is 5 or fewer.
719 */
720static int genDalvikArgsNoRange(CompilationUnit* cUnit, MIR* mir,
721 DecodedInstruction* dInsn, int callState,
722 ArmLIR** pcrLabel, bool isRange,
buzbee1da522d2011-09-04 11:22:20 -0700723 NextCallInsn nextCallInsn, ArmLIR* rollback,
724 bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700725{
726 RegLocation rlArg;
727 int registerArgs[3];
728
729 /* If no arguments, just return */
730 if (dInsn->vA == 0)
731 return callState;
732
buzbee561227c2011-09-02 15:28:19 -0700733 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700734
735 /*
736 * Load frame arguments arg4 & arg5 first. Coded a little odd to
737 * pre-schedule the method pointer target.
738 */
739 for (unsigned int i=3; i < dInsn->vA; i++) {
740 int reg;
buzbeeec5adf32011-09-11 15:25:43 -0700741 // Treating args as untyped 32-bit chunks
742 rlArg = oatGetRawSrc(cUnit, mir, i);
743 rlArg.wide = false;
744 rlArg = oatUpdateLoc(cUnit, rlArg);
buzbee67bf8852011-08-17 17:51:35 -0700745 if (rlArg.location == kLocPhysReg) {
746 reg = rlArg.lowReg;
747 } else {
buzbee109bd6a2011-09-06 13:58:41 -0700748 // r3 is the last arg register loaded, so can safely be used here
749 reg = r3;
750 loadValueDirectFixed(cUnit, rlArg, reg);
buzbee561227c2011-09-02 15:28:19 -0700751 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700752 }
753 storeBaseDisp(cUnit, rSP, (i + 1) * 4, reg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700754 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700755 }
756
757 /* Load register arguments r1..r3 */
buzbeee9a72f62011-09-04 17:59:07 -0700758 for (unsigned int i = 0; i < 3; i++) {
buzbee67bf8852011-08-17 17:51:35 -0700759 if (i < dInsn->vA)
760 registerArgs[i] = (isRange) ? dInsn->vC + i : i;
761 else
762 registerArgs[i] = INVALID_REG;
763 }
buzbeee9a72f62011-09-04 17:59:07 -0700764 if (skipThis) {
765 registerArgs[0] = INVALID_REG;
766 }
buzbee67bf8852011-08-17 17:51:35 -0700767 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
buzbee561227c2011-09-02 15:28:19 -0700768 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700769
buzbee6a0f7f52011-09-05 16:14:20 -0700770 //TODO: better to move this into CallInsn lists
buzbee67bf8852011-08-17 17:51:35 -0700771 // Load direct & need a "this" null check?
772 if (pcrLabel) {
buzbee5ade1d22011-09-09 14:44:52 -0700773 *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
buzbee67bf8852011-08-17 17:51:35 -0700774 }
775 return callState;
776}
777
778/*
779 * May have 0+ arguments (also used for jumbo). Note that
780 * source virtual registers may be in physical registers, so may
781 * need to be flushed to home location before copying. This
782 * applies to arg3 and above (see below).
783 *
784 * Two general strategies:
785 * If < 20 arguments
786 * Pass args 3-18 using vldm/vstm block copy
787 * Pass arg0, arg1 & arg2 in r1-r3
788 * If 20+ arguments
789 * Pass args arg19+ using memcpy block copy
790 * Pass arg0, arg1 & arg2 in r1-r3
791 *
792 */
793static int genDalvikArgsRange(CompilationUnit* cUnit, MIR* mir,
794 DecodedInstruction* dInsn, int callState,
buzbee561227c2011-09-02 15:28:19 -0700795 ArmLIR** pcrLabel, NextCallInsn nextCallInsn,
buzbee1da522d2011-09-04 11:22:20 -0700796 ArmLIR* rollback, bool skipThis)
buzbee67bf8852011-08-17 17:51:35 -0700797{
798 int firstArg = dInsn->vC;
799 int numArgs = dInsn->vA;
buzbeee9a72f62011-09-04 17:59:07 -0700800 int registerArgs[3];
801
buzbee67bf8852011-08-17 17:51:35 -0700802 // If we can treat it as non-range (Jumbo ops will use range form)
803 if (numArgs <= 5)
804 return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
buzbee1da522d2011-09-04 11:22:20 -0700805 true, nextCallInsn, rollback, skipThis);
buzbee67bf8852011-08-17 17:51:35 -0700806 /*
807 * Make sure range list doesn't span the break between in normal
808 * Dalvik vRegs and the ins.
809 */
buzbee1b4c8592011-08-31 10:43:51 -0700810 int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700811 int boundaryReg = cUnit->method->NumRegisters() - cUnit->method->NumIns();
buzbee1b4c8592011-08-31 10:43:51 -0700812 if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
813 LOG(FATAL) << "Argument list spanned locals & args";
buzbee67bf8852011-08-17 17:51:35 -0700814 }
815
816 /*
817 * First load the non-register arguments. Both forms expect all
818 * of the source arguments to be in their home frame location, so
819 * scan the sReg names and flush any that have been promoted to
820 * frame backing storage.
821 */
822 // Scan the rest of the args - if in physReg flush to memory
buzbee0c7f26d2011-09-07 12:28:51 -0700823 for (int i = 3; i < numArgs; i++) {
buzbeee9a72f62011-09-04 17:59:07 -0700824 RegLocation loc = oatGetRawSrc(cUnit, mir, i);
buzbee1b4c8592011-08-31 10:43:51 -0700825 if (loc.wide) {
826 loc = oatUpdateLocWide(cUnit, loc);
827 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
828 storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
829 loc.highReg);
buzbee561227c2011-09-02 15:28:19 -0700830 callState = nextCallInsn(cUnit, mir, dInsn, callState,
831 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700832 }
833 } else {
834 loc = oatUpdateLoc(cUnit, loc);
835 if (loc.location == kLocPhysReg) { // TUNING: if dirty?
836 storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
buzbee561227c2011-09-02 15:28:19 -0700837 callState = nextCallInsn(cUnit, mir, dInsn, callState,
838 rollback);
buzbee1b4c8592011-08-31 10:43:51 -0700839 }
buzbee67bf8852011-08-17 17:51:35 -0700840 }
841 }
842
843 int startOffset = cUnit->regLocation[mir->ssaRep->uses[3]].spOffset;
844 int outsOffset = 4 /* Method* */ + (3 * 4);
845 if (numArgs >= 20) {
buzbeec0fe6c72011-09-18 20:19:14 -0700846 // Generate memcpy
847 opRegRegImm(cUnit, kOpAdd, r0, rSP, outsOffset);
848 opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700849 loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
850 loadConstant(cUnit, r2, (numArgs - 3) * 4);
Ian Rogersff1ed472011-09-20 13:46:24 -0700851 callRuntimeHelper(cUnit, rLR);
buzbee010cffc2011-09-21 18:28:43 -0700852 // Restore Method*
853 loadCurrMethodDirect(cUnit, r0);
buzbee67bf8852011-08-17 17:51:35 -0700854 } else {
855 // Use vldm/vstm pair using r3 as a temp
buzbeec143c552011-08-20 17:38:58 -0700856 int regsLeft = std::min(numArgs - 3, 16);
buzbee561227c2011-09-02 15:28:19 -0700857 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700858 opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
buzbeef48e9712011-09-15 17:54:28 -0700859 ArmLIR* ld = newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
860 //TUNING: loosen barrier
861 ld->defMask = ENCODE_ALL;
862 setMemRefType(ld, true /* isLoad */, kDalvikReg);
buzbee561227c2011-09-02 15:28:19 -0700863 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700864 opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
buzbee561227c2011-09-02 15:28:19 -0700865 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbeef48e9712011-09-15 17:54:28 -0700866 ArmLIR* st = newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
867 setMemRefType(st, false /* isLoad */, kDalvikReg);
868 st->defMask = ENCODE_ALL;
buzbee561227c2011-09-02 15:28:19 -0700869 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700870 }
871
872 // Handle the 1st 3 in r1, r2 & r3
buzbeee9a72f62011-09-04 17:59:07 -0700873 for (unsigned int i = 0; i < 3; i++) {
874 if (i < dInsn->vA)
875 registerArgs[i] = dInsn->vC + i;
876 else
877 registerArgs[i] = INVALID_REG;
buzbee67bf8852011-08-17 17:51:35 -0700878 }
buzbeee9a72f62011-09-04 17:59:07 -0700879 if (skipThis) {
880 registerArgs[0] = INVALID_REG;
881 }
882 callState = loadArgRegs(cUnit, mir, dInsn, callState, registerArgs,
883 nextCallInsn, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700884
buzbee561227c2011-09-02 15:28:19 -0700885 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -0700886 return callState;
887}
888
buzbee2a475e72011-09-07 17:19:17 -0700889#ifdef DISPLAY_MISSING_TARGETS
890// Debugging routine - if null target, branch to DebugMe
891static void genShowTarget(CompilationUnit* cUnit)
892{
893 ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, rLR, 0);
894 loadWordDisp(cUnit, rSELF,
895 OFFSETOF_MEMBER(Thread, pDebugMe), rLR);
896 ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
897 target->defMask = -1;
898 branchOver->generic.target = (LIR*)target;
899}
900#endif
901
buzbee561227c2011-09-02 15:28:19 -0700902static void genInvokeStaticDirect(CompilationUnit* cUnit, MIR* mir,
903 bool direct, bool range)
buzbee67bf8852011-08-17 17:51:35 -0700904{
905 DecodedInstruction* dInsn = &mir->dalvikInsn;
906 int callState = 0;
907 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -0700908 ArmLIR** pNullCk = direct ? &nullCk : NULL;
buzbee561227c2011-09-02 15:28:19 -0700909 NextCallInsn nextCallInsn = nextSDCallInsn;
910
buzbee109bd6a2011-09-06 13:58:41 -0700911 // Explicit register usage
912 oatLockCallTemps(cUnit);
913
buzbee561227c2011-09-02 15:28:19 -0700914 if (range) {
915 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700916 nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700917 } else {
918 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
buzbee1da522d2011-09-04 11:22:20 -0700919 false, nextCallInsn, NULL, false);
buzbee561227c2011-09-02 15:28:19 -0700920 }
buzbee67bf8852011-08-17 17:51:35 -0700921 // Finish up any of the call sequence not interleaved in arg loading
922 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700923 callState = nextCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700924 }
buzbee2a475e72011-09-07 17:19:17 -0700925#ifdef DISPLAY_MISSING_TARGETS
926 genShowTarget(cUnit);
927#endif
buzbeeec5adf32011-09-11 15:25:43 -0700928 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700929}
930
buzbee4a3164f2011-09-03 11:25:10 -0700931/*
932 * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
933 * which will locate the target and continue on via a tail call.
934 */
buzbee67bf8852011-08-17 17:51:35 -0700935static void genInvokeInterface(CompilationUnit* cUnit, MIR* mir)
936{
937 DecodedInstruction* dInsn = &mir->dalvikInsn;
938 int callState = 0;
939 ArmLIR* nullCk;
buzbee109bd6a2011-09-06 13:58:41 -0700940
941 // Explicit register usage
942 oatLockCallTemps(cUnit);
buzbee67bf8852011-08-17 17:51:35 -0700943 /* Note: must call nextInterfaceCallInsn() prior to 1st argument load */
buzbee561227c2011-09-02 15:28:19 -0700944 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700945 if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
946 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -0700947 false, nextInterfaceCallInsn, NULL,
buzbee367ce0b2011-09-14 23:19:50 -0700948 false);
buzbee67bf8852011-08-17 17:51:35 -0700949 else
950 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee367ce0b2011-09-14 23:19:50 -0700951 nextInterfaceCallInsn, NULL, false);
buzbee67bf8852011-08-17 17:51:35 -0700952 // Finish up any of the call sequence not interleaved in arg loading
953 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -0700954 callState = nextInterfaceCallInsn(cUnit, mir, dInsn, callState, NULL);
buzbee67bf8852011-08-17 17:51:35 -0700955 }
buzbee2a475e72011-09-07 17:19:17 -0700956#ifdef DISPLAY_MISSING_TARGETS
957 genShowTarget(cUnit);
958#endif
buzbeeec5adf32011-09-11 15:25:43 -0700959 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -0700960}
961
962static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
963{
964 DecodedInstruction* dInsn = &mir->dalvikInsn;
965 int callState = 0;
966 ArmLIR* nullCk;
buzbee4a3164f2011-09-03 11:25:10 -0700967 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -0700968 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
969 Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee4a3164f2011-09-03 11:25:10 -0700970 NextCallInsn nextCallInsn;
971 bool fastPath = true;
buzbee109bd6a2011-09-06 13:58:41 -0700972
973 // Explicit register usage
974 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -0700975 if (SLOW_INVOKE_PATH || baseMethod == NULL) {
buzbee4a3164f2011-09-03 11:25:10 -0700976 fastPath = false;
977 } else {
978 Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
979 if (superClass == NULL) {
980 fastPath = false;
981 } else {
982 int32_t target_idx = baseMethod->GetMethodIndex();
983 if (superClass->GetVTable()->GetLength() <= target_idx) {
984 fastPath = false;
985 } else {
986 fastPath = (superClass->GetVTable()->Get(target_idx) != NULL);
987 }
988 }
989 }
990 if (fastPath) {
991 nextCallInsn = nextSuperCallInsn;
992 rollback = NULL;
993 } else {
994 nextCallInsn = nextSuperCallInsnSP;
995 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
996 rollback->defMask = -1;
997 }
buzbee67bf8852011-08-17 17:51:35 -0700998 if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
999 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001000 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001001 else
1002 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001003 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001004 // Finish up any of the call sequence not interleaved in arg loading
1005 while (callState >= 0) {
buzbee6a0f7f52011-09-05 16:14:20 -07001006 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001007 }
buzbee2a475e72011-09-07 17:19:17 -07001008#ifdef DISPLAY_MISSING_TARGETS
1009 genShowTarget(cUnit);
1010#endif
buzbeeec5adf32011-09-11 15:25:43 -07001011 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001012}
1013
1014static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
1015{
1016 DecodedInstruction* dInsn = &mir->dalvikInsn;
1017 int callState = 0;
1018 ArmLIR* nullCk;
buzbee561227c2011-09-02 15:28:19 -07001019 ArmLIR* rollback;
Brian Carlstrom845490b2011-09-19 15:56:53 -07001020 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
1021 Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
buzbee561227c2011-09-02 15:28:19 -07001022 NextCallInsn nextCallInsn;
buzbee7b1b86d2011-08-26 18:59:10 -07001023
buzbee109bd6a2011-09-06 13:58:41 -07001024 // Explicit register usage
1025 oatLockCallTemps(cUnit);
buzbee34cd9e52011-09-08 14:31:52 -07001026 if (SLOW_INVOKE_PATH || method == NULL) {
buzbee561227c2011-09-02 15:28:19 -07001027 // Slow path
1028 nextCallInsn = nextVCallInsnSP;
1029 // If we need a slow-path callout, we'll restart here
1030 rollback = newLIR0(cUnit, kArmPseudoTargetLabel);
1031 rollback->defMask = -1;
1032 } else {
1033 // Fast path
1034 nextCallInsn = nextVCallInsn;
1035 rollback = NULL;
1036 }
buzbee67bf8852011-08-17 17:51:35 -07001037 if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
1038 callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001039 false, nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001040 else
1041 callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
buzbee1da522d2011-09-04 11:22:20 -07001042 nextCallInsn, rollback, true);
buzbee67bf8852011-08-17 17:51:35 -07001043 // Finish up any of the call sequence not interleaved in arg loading
1044 while (callState >= 0) {
buzbee561227c2011-09-02 15:28:19 -07001045 callState = nextCallInsn(cUnit, mir, dInsn, callState, rollback);
buzbee67bf8852011-08-17 17:51:35 -07001046 }
buzbee2a475e72011-09-07 17:19:17 -07001047#ifdef DISPLAY_MISSING_TARGETS
1048 genShowTarget(cUnit);
1049#endif
buzbeeec5adf32011-09-11 15:25:43 -07001050 opReg(cUnit, kOpBlx, rLR);
buzbee67bf8852011-08-17 17:51:35 -07001051}
1052
buzbee67bf8852011-08-17 17:51:35 -07001053static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
1054 BasicBlock* bb, ArmLIR* labelList)
1055{
1056 bool res = false; // Assume success
1057 RegLocation rlSrc[3];
1058 RegLocation rlDest = badLoc;
1059 RegLocation rlResult = badLoc;
1060 Opcode opcode = mir->dalvikInsn.opcode;
1061
1062 /* Prep Src and Dest locations */
1063 int nextSreg = 0;
1064 int nextLoc = 0;
1065 int attrs = oatDataFlowAttributes[opcode];
1066 rlSrc[0] = rlSrc[1] = rlSrc[2] = badLoc;
1067 if (attrs & DF_UA) {
1068 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1069 nextSreg++;
1070 } else if (attrs & DF_UA_WIDE) {
1071 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1072 nextSreg + 1);
1073 nextSreg+= 2;
1074 }
1075 if (attrs & DF_UB) {
1076 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1077 nextSreg++;
1078 } else if (attrs & DF_UB_WIDE) {
1079 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1080 nextSreg + 1);
1081 nextSreg+= 2;
1082 }
1083 if (attrs & DF_UC) {
1084 rlSrc[nextLoc++] = oatGetSrc(cUnit, mir, nextSreg);
1085 } else if (attrs & DF_UC_WIDE) {
1086 rlSrc[nextLoc++] = oatGetSrcWide(cUnit, mir, nextSreg,
1087 nextSreg + 1);
1088 }
1089 if (attrs & DF_DA) {
1090 rlDest = oatGetDest(cUnit, mir, 0);
1091 } else if (attrs & DF_DA_WIDE) {
1092 rlDest = oatGetDestWide(cUnit, mir, 0, 1);
1093 }
1094
1095 switch(opcode) {
1096 case OP_NOP:
1097 break;
1098
1099 case OP_MOVE_EXCEPTION:
1100 int exOffset;
1101 int resetReg;
buzbeec143c552011-08-20 17:38:58 -07001102 exOffset = Thread::ExceptionOffset().Int32Value();
buzbee67bf8852011-08-17 17:51:35 -07001103 resetReg = oatAllocTemp(cUnit);
1104 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1105 loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
1106 loadConstant(cUnit, resetReg, 0);
1107 storeWordDisp(cUnit, rSELF, exOffset, resetReg);
1108 storeValue(cUnit, rlDest, rlResult);
1109 break;
1110
1111 case OP_RETURN_VOID:
1112 break;
1113
1114 case OP_RETURN:
1115 case OP_RETURN_OBJECT:
buzbeec1f45042011-09-21 16:03:19 -07001116 genSuspendPoll(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001117 storeValue(cUnit, retLoc, rlSrc[0]);
1118 break;
1119
1120 case OP_RETURN_WIDE:
buzbeec1f45042011-09-21 16:03:19 -07001121 genSuspendPoll(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001122 rlDest = retLocWide;
1123 rlDest.fp = rlSrc[0].fp;
1124 storeValueWide(cUnit, rlDest, rlSrc[0]);
1125 break;
1126
1127 case OP_MOVE_RESULT_WIDE:
buzbee43a36422011-09-14 14:00:13 -07001128 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001129 break; // Nop - combined w/ previous invoke
1130 /*
1131 * Somewhat hacky here. Because we're now passing
1132 * return values in registers, we have to let the
1133 * register allocation utilities know that the return
1134 * registers are live and may not be used for address
1135 * formation in storeValueWide.
1136 */
1137 assert(retLocWide.lowReg == r0);
buzbee1da522d2011-09-04 11:22:20 -07001138 assert(retLocWide.highReg == r1);
buzbee67bf8852011-08-17 17:51:35 -07001139 oatLockTemp(cUnit, retLocWide.lowReg);
1140 oatLockTemp(cUnit, retLocWide.highReg);
1141 storeValueWide(cUnit, rlDest, retLocWide);
1142 oatFreeTemp(cUnit, retLocWide.lowReg);
1143 oatFreeTemp(cUnit, retLocWide.highReg);
1144 break;
1145
1146 case OP_MOVE_RESULT:
1147 case OP_MOVE_RESULT_OBJECT:
buzbee43a36422011-09-14 14:00:13 -07001148 if (mir->optimizationFlags & MIR_INLINED)
buzbee67bf8852011-08-17 17:51:35 -07001149 break; // Nop - combined w/ previous invoke
1150 /* See comment for OP_MOVE_RESULT_WIDE */
1151 assert(retLoc.lowReg == r0);
1152 oatLockTemp(cUnit, retLoc.lowReg);
1153 storeValue(cUnit, rlDest, retLoc);
1154 oatFreeTemp(cUnit, retLoc.lowReg);
1155 break;
1156
1157 case OP_MOVE:
1158 case OP_MOVE_OBJECT:
1159 case OP_MOVE_16:
1160 case OP_MOVE_OBJECT_16:
1161 case OP_MOVE_FROM16:
1162 case OP_MOVE_OBJECT_FROM16:
1163 storeValue(cUnit, rlDest, rlSrc[0]);
1164 break;
1165
1166 case OP_MOVE_WIDE:
1167 case OP_MOVE_WIDE_16:
1168 case OP_MOVE_WIDE_FROM16:
1169 storeValueWide(cUnit, rlDest, rlSrc[0]);
1170 break;
1171
1172 case OP_CONST:
1173 case OP_CONST_4:
1174 case OP_CONST_16:
1175 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1176 loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
1177 storeValue(cUnit, rlDest, rlResult);
1178 break;
1179
1180 case OP_CONST_HIGH16:
1181 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1182 loadConstantNoClobber(cUnit, rlResult.lowReg,
1183 mir->dalvikInsn.vB << 16);
1184 storeValue(cUnit, rlDest, rlResult);
1185 break;
1186
1187 case OP_CONST_WIDE_16:
1188 case OP_CONST_WIDE_32:
buzbee03fa2632011-09-20 17:10:57 -07001189 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1190 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1191 mir->dalvikInsn.vB,
1192 (mir->dalvikInsn.vB & 0x80000000) ? -1 : 0);
buzbee67bf8852011-08-17 17:51:35 -07001193 storeValueWide(cUnit, rlDest, rlResult);
1194 break;
1195
1196 case OP_CONST_WIDE:
1197 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1198 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
buzbee54330722011-08-23 16:46:55 -07001199 mir->dalvikInsn.vB_wide & 0xffffffff,
1200 (mir->dalvikInsn.vB_wide >> 32) & 0xffffffff);
buzbee3ea4ec52011-08-22 17:37:19 -07001201 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001202 break;
1203
1204 case OP_CONST_WIDE_HIGH16:
1205 rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
1206 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
1207 0, mir->dalvikInsn.vB << 16);
buzbee7b1b86d2011-08-26 18:59:10 -07001208 storeValueWide(cUnit, rlDest, rlResult);
buzbee67bf8852011-08-17 17:51:35 -07001209 break;
1210
1211 case OP_MONITOR_ENTER:
1212 genMonitorEnter(cUnit, mir, rlSrc[0]);
1213 break;
1214
1215 case OP_MONITOR_EXIT:
1216 genMonitorExit(cUnit, mir, rlSrc[0]);
1217 break;
1218
1219 case OP_CHECK_CAST:
1220 genCheckCast(cUnit, mir, rlSrc[0]);
1221 break;
1222
1223 case OP_INSTANCE_OF:
1224 genInstanceof(cUnit, mir, rlDest, rlSrc[0]);
1225 break;
1226
1227 case OP_NEW_INSTANCE:
1228 genNewInstance(cUnit, mir, rlDest);
1229 break;
1230
1231 case OP_THROW:
1232 genThrow(cUnit, mir, rlSrc[0]);
1233 break;
1234
buzbee5ade1d22011-09-09 14:44:52 -07001235 case OP_THROW_VERIFICATION_ERROR:
1236 loadWordDisp(cUnit, rSELF,
1237 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
1238 loadConstant(cUnit, r0, mir->dalvikInsn.vA);
1239 loadConstant(cUnit, r1, mir->dalvikInsn.vB);
Ian Rogersff1ed472011-09-20 13:46:24 -07001240 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07001241 break;
1242
buzbee67bf8852011-08-17 17:51:35 -07001243 case OP_ARRAY_LENGTH:
1244 int lenOffset;
buzbeec143c552011-08-20 17:38:58 -07001245 lenOffset = Array::LengthOffset().Int32Value();
buzbee7b1b86d2011-08-26 18:59:10 -07001246 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
buzbee5ade1d22011-09-09 14:44:52 -07001247 genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
buzbee67bf8852011-08-17 17:51:35 -07001248 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1249 loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
1250 rlResult.lowReg);
1251 storeValue(cUnit, rlDest, rlResult);
1252 break;
1253
1254 case OP_CONST_STRING:
1255 case OP_CONST_STRING_JUMBO:
1256 genConstString(cUnit, mir, rlDest, rlSrc[0]);
1257 break;
1258
1259 case OP_CONST_CLASS:
1260 genConstClass(cUnit, mir, rlDest, rlSrc[0]);
1261 break;
1262
1263 case OP_FILL_ARRAY_DATA:
1264 genFillArrayData(cUnit, mir, rlSrc[0]);
1265 break;
1266
1267 case OP_FILLED_NEW_ARRAY:
1268 genFilledNewArray(cUnit, mir, false /* not range */);
1269 break;
1270
1271 case OP_FILLED_NEW_ARRAY_RANGE:
1272 genFilledNewArray(cUnit, mir, true /* range */);
1273 break;
1274
1275 case OP_NEW_ARRAY:
1276 genNewArray(cUnit, mir, rlDest, rlSrc[0]);
1277 break;
1278
1279 case OP_GOTO:
1280 case OP_GOTO_16:
1281 case OP_GOTO_32:
buzbeec1f45042011-09-21 16:03:19 -07001282 if (bb->taken->startOffset <= mir->offset) {
1283 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001284 }
1285 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1286 break;
1287
1288 case OP_PACKED_SWITCH:
1289 genPackedSwitch(cUnit, mir, rlSrc[0]);
1290 break;
1291
1292 case OP_SPARSE_SWITCH:
1293 genSparseSwitch(cUnit, mir, rlSrc[0]);
1294 break;
1295
1296 case OP_CMPL_FLOAT:
1297 case OP_CMPG_FLOAT:
1298 case OP_CMPL_DOUBLE:
1299 case OP_CMPG_DOUBLE:
1300 res = genCmpFP(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1301 break;
1302
1303 case OP_CMP_LONG:
1304 genCmpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1305 break;
1306
1307 case OP_IF_EQ:
1308 case OP_IF_NE:
1309 case OP_IF_LT:
1310 case OP_IF_GE:
1311 case OP_IF_GT:
1312 case OP_IF_LE: {
1313 bool backwardBranch;
1314 ArmConditionCode cond;
1315 backwardBranch = (bb->taken->startOffset <= mir->offset);
1316 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001317 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001318 }
1319 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1320 rlSrc[1] = loadValue(cUnit, rlSrc[1], kCoreReg);
1321 opRegReg(cUnit, kOpCmp, rlSrc[0].lowReg, rlSrc[1].lowReg);
1322 switch(opcode) {
1323 case OP_IF_EQ:
1324 cond = kArmCondEq;
1325 break;
1326 case OP_IF_NE:
1327 cond = kArmCondNe;
1328 break;
1329 case OP_IF_LT:
1330 cond = kArmCondLt;
1331 break;
1332 case OP_IF_GE:
1333 cond = kArmCondGe;
1334 break;
1335 case OP_IF_GT:
1336 cond = kArmCondGt;
1337 break;
1338 case OP_IF_LE:
1339 cond = kArmCondLe;
1340 break;
1341 default:
1342 cond = (ArmConditionCode)0;
1343 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1344 }
1345 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1346 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1347 break;
1348 }
1349
1350 case OP_IF_EQZ:
1351 case OP_IF_NEZ:
1352 case OP_IF_LTZ:
1353 case OP_IF_GEZ:
1354 case OP_IF_GTZ:
1355 case OP_IF_LEZ: {
1356 bool backwardBranch;
1357 ArmConditionCode cond;
1358 backwardBranch = (bb->taken->startOffset <= mir->offset);
1359 if (backwardBranch) {
buzbeec1f45042011-09-21 16:03:19 -07001360 genSuspendTest(cUnit, mir);
buzbee67bf8852011-08-17 17:51:35 -07001361 }
1362 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1363 opRegImm(cUnit, kOpCmp, rlSrc[0].lowReg, 0);
1364 switch(opcode) {
1365 case OP_IF_EQZ:
1366 cond = kArmCondEq;
1367 break;
1368 case OP_IF_NEZ:
1369 cond = kArmCondNe;
1370 break;
1371 case OP_IF_LTZ:
1372 cond = kArmCondLt;
1373 break;
1374 case OP_IF_GEZ:
1375 cond = kArmCondGe;
1376 break;
1377 case OP_IF_GTZ:
1378 cond = kArmCondGt;
1379 break;
1380 case OP_IF_LEZ:
1381 cond = kArmCondLe;
1382 break;
1383 default:
1384 cond = (ArmConditionCode)0;
1385 LOG(FATAL) << "Unexpected opcode " << (int)opcode;
1386 }
1387 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
1388 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
1389 break;
1390 }
1391
1392 case OP_AGET_WIDE:
1393 genArrayGet(cUnit, mir, kLong, rlSrc[0], rlSrc[1], rlDest, 3);
1394 break;
1395 case OP_AGET:
1396 case OP_AGET_OBJECT:
1397 genArrayGet(cUnit, mir, kWord, rlSrc[0], rlSrc[1], rlDest, 2);
1398 break;
1399 case OP_AGET_BOOLEAN:
1400 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1],
1401 rlDest, 0);
1402 break;
1403 case OP_AGET_BYTE:
1404 genArrayGet(cUnit, mir, kSignedByte, rlSrc[0], rlSrc[1], rlDest, 0);
1405 break;
1406 case OP_AGET_CHAR:
1407 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1],
1408 rlDest, 1);
1409 break;
1410 case OP_AGET_SHORT:
1411 genArrayGet(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], rlDest, 1);
1412 break;
1413 case OP_APUT_WIDE:
1414 genArrayPut(cUnit, mir, kLong, rlSrc[1], rlSrc[2], rlSrc[0], 3);
1415 break;
1416 case OP_APUT:
1417 genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
1418 break;
1419 case OP_APUT_OBJECT:
buzbee1b4c8592011-08-31 10:43:51 -07001420 genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
buzbee67bf8852011-08-17 17:51:35 -07001421 break;
1422 case OP_APUT_SHORT:
1423 case OP_APUT_CHAR:
1424 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc[1], rlSrc[2],
1425 rlSrc[0], 1);
1426 break;
1427 case OP_APUT_BYTE:
1428 case OP_APUT_BOOLEAN:
1429 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc[1], rlSrc[2],
1430 rlSrc[0], 0);
1431 break;
1432
1433 case OP_IGET_WIDE:
1434 case OP_IGET_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001435 genIGetWide(cUnit, mir, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001436 break;
1437
1438 case OP_IGET:
1439 case OP_IGET_VOLATILE:
1440 case OP_IGET_OBJECT:
1441 case OP_IGET_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001442 genIGet(cUnit, mir, kWord, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001443 break;
1444
1445 case OP_IGET_BOOLEAN:
1446 case OP_IGET_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001447 genIGet(cUnit, mir, kUnsignedByte, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001448 break;
1449
1450 case OP_IGET_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001451 genIGet(cUnit, mir, kUnsignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001452 break;
1453
1454 case OP_IGET_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001455 genIGet(cUnit, mir, kSignedHalf, rlDest, rlSrc[0]);
buzbee67bf8852011-08-17 17:51:35 -07001456 break;
1457
1458 case OP_IPUT_WIDE:
1459 case OP_IPUT_WIDE_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001460 genIPutWide(cUnit, mir, rlSrc[0], rlSrc[1]);
buzbee67bf8852011-08-17 17:51:35 -07001461 break;
1462
1463 case OP_IPUT_OBJECT:
1464 case OP_IPUT_OBJECT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001465 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], true);
buzbee67bf8852011-08-17 17:51:35 -07001466 break;
1467
1468 case OP_IPUT:
1469 case OP_IPUT_VOLATILE:
buzbee43a36422011-09-14 14:00:13 -07001470 genIPut(cUnit, mir, kWord, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001471 break;
1472
1473 case OP_IPUT_BOOLEAN:
1474 case OP_IPUT_BYTE:
buzbee43a36422011-09-14 14:00:13 -07001475 genIPut(cUnit, mir, kUnsignedByte, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001476 break;
1477
1478 case OP_IPUT_CHAR:
buzbee43a36422011-09-14 14:00:13 -07001479 genIPut(cUnit, mir, kUnsignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001480 break;
1481
1482 case OP_IPUT_SHORT:
buzbee43a36422011-09-14 14:00:13 -07001483 genIPut(cUnit, mir, kSignedHalf, rlSrc[0], rlSrc[1], false);
buzbee67bf8852011-08-17 17:51:35 -07001484 break;
1485
1486 case OP_SGET:
1487 case OP_SGET_OBJECT:
1488 case OP_SGET_BOOLEAN:
1489 case OP_SGET_BYTE:
1490 case OP_SGET_CHAR:
1491 case OP_SGET_SHORT:
1492 genSget(cUnit, mir, rlResult, rlDest);
1493 break;
1494
1495 case OP_SGET_WIDE:
1496 genSgetWide(cUnit, mir, rlResult, rlDest);
1497 break;
1498
1499 case OP_SPUT:
1500 case OP_SPUT_OBJECT:
1501 case OP_SPUT_BOOLEAN:
1502 case OP_SPUT_BYTE:
1503 case OP_SPUT_CHAR:
1504 case OP_SPUT_SHORT:
1505 genSput(cUnit, mir, rlSrc[0]);
1506 break;
1507
1508 case OP_SPUT_WIDE:
1509 genSputWide(cUnit, mir, rlSrc[0]);
1510 break;
1511
1512 case OP_INVOKE_STATIC_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001513 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1514 true /*range*/);
1515 break;
buzbee67bf8852011-08-17 17:51:35 -07001516 case OP_INVOKE_STATIC:
buzbee561227c2011-09-02 15:28:19 -07001517 genInvokeStaticDirect(cUnit, mir, false /*direct*/,
1518 false /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001519 break;
1520
1521 case OP_INVOKE_DIRECT:
buzbee561227c2011-09-02 15:28:19 -07001522 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1523 false /*range*/);
1524 break;
buzbee67bf8852011-08-17 17:51:35 -07001525 case OP_INVOKE_DIRECT_RANGE:
buzbee561227c2011-09-02 15:28:19 -07001526 genInvokeStaticDirect(cUnit, mir, true /*direct*/,
1527 true /*range*/);
buzbee67bf8852011-08-17 17:51:35 -07001528 break;
1529
1530 case OP_INVOKE_VIRTUAL:
1531 case OP_INVOKE_VIRTUAL_RANGE:
1532 genInvokeVirtual(cUnit, mir);
1533 break;
1534
1535 case OP_INVOKE_SUPER:
1536 case OP_INVOKE_SUPER_RANGE:
1537 genInvokeSuper(cUnit, mir);
1538 break;
1539
1540 case OP_INVOKE_INTERFACE:
1541 case OP_INVOKE_INTERFACE_RANGE:
1542 genInvokeInterface(cUnit, mir);
1543 break;
1544
1545 case OP_NEG_INT:
1546 case OP_NOT_INT:
1547 res = genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1548 break;
1549
1550 case OP_NEG_LONG:
1551 case OP_NOT_LONG:
1552 res = genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1553 break;
1554
1555 case OP_NEG_FLOAT:
1556 res = genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1557 break;
1558
1559 case OP_NEG_DOUBLE:
1560 res = genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[0]);
1561 break;
1562
1563 case OP_INT_TO_LONG:
1564 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1565 if (rlSrc[0].location == kLocPhysReg) {
1566 genRegCopy(cUnit, rlResult.lowReg, rlSrc[0].lowReg);
1567 } else {
1568 loadValueDirect(cUnit, rlSrc[0], rlResult.lowReg);
1569 }
1570 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
1571 rlResult.lowReg, 31);
1572 storeValueWide(cUnit, rlDest, rlResult);
1573 break;
1574
1575 case OP_LONG_TO_INT:
1576 rlSrc[0] = oatUpdateLocWide(cUnit, rlSrc[0]);
1577 rlSrc[0] = oatWideToNarrow(cUnit, rlSrc[0]);
1578 storeValue(cUnit, rlDest, rlSrc[0]);
1579 break;
1580
1581 case OP_INT_TO_BYTE:
1582 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1583 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1584 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc[0].lowReg);
1585 storeValue(cUnit, rlDest, rlResult);
1586 break;
1587
1588 case OP_INT_TO_SHORT:
1589 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1590 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1591 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc[0].lowReg);
1592 storeValue(cUnit, rlDest, rlResult);
1593 break;
1594
1595 case OP_INT_TO_CHAR:
1596 rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
1597 rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
1598 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc[0].lowReg);
1599 storeValue(cUnit, rlDest, rlResult);
1600 break;
1601
1602 case OP_INT_TO_FLOAT:
1603 case OP_INT_TO_DOUBLE:
1604 case OP_LONG_TO_FLOAT:
1605 case OP_LONG_TO_DOUBLE:
1606 case OP_FLOAT_TO_INT:
1607 case OP_FLOAT_TO_LONG:
1608 case OP_FLOAT_TO_DOUBLE:
1609 case OP_DOUBLE_TO_INT:
1610 case OP_DOUBLE_TO_LONG:
1611 case OP_DOUBLE_TO_FLOAT:
1612 genConversion(cUnit, mir);
1613 break;
1614
1615 case OP_ADD_INT:
1616 case OP_SUB_INT:
1617 case OP_MUL_INT:
1618 case OP_DIV_INT:
1619 case OP_REM_INT:
1620 case OP_AND_INT:
1621 case OP_OR_INT:
1622 case OP_XOR_INT:
1623 case OP_SHL_INT:
1624 case OP_SHR_INT:
1625 case OP_USHR_INT:
1626 case OP_ADD_INT_2ADDR:
1627 case OP_SUB_INT_2ADDR:
1628 case OP_MUL_INT_2ADDR:
1629 case OP_DIV_INT_2ADDR:
1630 case OP_REM_INT_2ADDR:
1631 case OP_AND_INT_2ADDR:
1632 case OP_OR_INT_2ADDR:
1633 case OP_XOR_INT_2ADDR:
1634 case OP_SHL_INT_2ADDR:
1635 case OP_SHR_INT_2ADDR:
1636 case OP_USHR_INT_2ADDR:
1637 genArithOpInt(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1638 break;
1639
1640 case OP_ADD_LONG:
1641 case OP_SUB_LONG:
1642 case OP_MUL_LONG:
1643 case OP_DIV_LONG:
1644 case OP_REM_LONG:
1645 case OP_AND_LONG:
1646 case OP_OR_LONG:
1647 case OP_XOR_LONG:
1648 case OP_ADD_LONG_2ADDR:
1649 case OP_SUB_LONG_2ADDR:
1650 case OP_MUL_LONG_2ADDR:
1651 case OP_DIV_LONG_2ADDR:
1652 case OP_REM_LONG_2ADDR:
1653 case OP_AND_LONG_2ADDR:
1654 case OP_OR_LONG_2ADDR:
1655 case OP_XOR_LONG_2ADDR:
1656 genArithOpLong(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1657 break;
1658
buzbee67bf8852011-08-17 17:51:35 -07001659 case OP_SHL_LONG:
1660 case OP_SHR_LONG:
1661 case OP_USHR_LONG:
buzbeee6d61962011-08-27 11:58:19 -07001662 case OP_SHL_LONG_2ADDR:
1663 case OP_SHR_LONG_2ADDR:
1664 case OP_USHR_LONG_2ADDR:
buzbee67bf8852011-08-17 17:51:35 -07001665 genShiftOpLong(cUnit,mir, rlDest, rlSrc[0], rlSrc[1]);
1666 break;
1667
1668 case OP_ADD_FLOAT:
1669 case OP_SUB_FLOAT:
1670 case OP_MUL_FLOAT:
1671 case OP_DIV_FLOAT:
1672 case OP_REM_FLOAT:
1673 case OP_ADD_FLOAT_2ADDR:
1674 case OP_SUB_FLOAT_2ADDR:
1675 case OP_MUL_FLOAT_2ADDR:
1676 case OP_DIV_FLOAT_2ADDR:
1677 case OP_REM_FLOAT_2ADDR:
1678 genArithOpFloat(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1679 break;
1680
1681 case OP_ADD_DOUBLE:
1682 case OP_SUB_DOUBLE:
1683 case OP_MUL_DOUBLE:
1684 case OP_DIV_DOUBLE:
1685 case OP_REM_DOUBLE:
1686 case OP_ADD_DOUBLE_2ADDR:
1687 case OP_SUB_DOUBLE_2ADDR:
1688 case OP_MUL_DOUBLE_2ADDR:
1689 case OP_DIV_DOUBLE_2ADDR:
1690 case OP_REM_DOUBLE_2ADDR:
1691 genArithOpDouble(cUnit, mir, rlDest, rlSrc[0], rlSrc[1]);
1692 break;
1693
1694 case OP_RSUB_INT:
1695 case OP_ADD_INT_LIT16:
1696 case OP_MUL_INT_LIT16:
1697 case OP_DIV_INT_LIT16:
1698 case OP_REM_INT_LIT16:
1699 case OP_AND_INT_LIT16:
1700 case OP_OR_INT_LIT16:
1701 case OP_XOR_INT_LIT16:
1702 case OP_ADD_INT_LIT8:
1703 case OP_RSUB_INT_LIT8:
1704 case OP_MUL_INT_LIT8:
1705 case OP_DIV_INT_LIT8:
1706 case OP_REM_INT_LIT8:
1707 case OP_AND_INT_LIT8:
1708 case OP_OR_INT_LIT8:
1709 case OP_XOR_INT_LIT8:
1710 case OP_SHL_INT_LIT8:
1711 case OP_SHR_INT_LIT8:
1712 case OP_USHR_INT_LIT8:
1713 genArithOpIntLit(cUnit, mir, rlDest, rlSrc[0], mir->dalvikInsn.vC);
1714 break;
1715
1716 default:
1717 res = true;
1718 }
1719 return res;
1720}
1721
1722static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
1723 "kMirOpPhi",
1724 "kMirOpNullNRangeUpCheck",
1725 "kMirOpNullNRangeDownCheck",
1726 "kMirOpLowerBound",
1727 "kMirOpPunt",
1728 "kMirOpCheckInlinePrediction",
1729};
1730
1731/* Extended MIR instructions like PHI */
1732static void handleExtendedMethodMIR(CompilationUnit* cUnit, MIR* mir)
1733{
1734 int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
1735 char* msg = (char*)oatNew(strlen(extendedMIROpNames[opOffset]) + 1, false);
1736 strcpy(msg, extendedMIROpNames[opOffset]);
1737 ArmLIR* op = newLIR1(cUnit, kArmPseudoExtended, (int) msg);
1738
1739 switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
1740 case kMirOpPhi: {
1741 char* ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1742 op->flags.isNop = true;
1743 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1744 break;
1745 }
1746 default:
1747 break;
1748 }
1749}
1750
1751/* If there are any ins passed in registers that have not been promoted
1752 * to a callee-save register, flush them to the frame.
buzbeedfd3d702011-08-28 12:56:51 -07001753 * Note: at this pointCopy any ins that are passed in register to their
1754 * home location */
buzbee67bf8852011-08-17 17:51:35 -07001755static void flushIns(CompilationUnit* cUnit)
1756{
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001757 if (cUnit->method->NumIns() == 0)
buzbee67bf8852011-08-17 17:51:35 -07001758 return;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001759 int inRegs = (cUnit->method->NumIns() > 2) ? 3
1760 : cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001761 int startReg = r1;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001762 int startLoc = cUnit->method->NumRegisters() -
1763 cUnit->method->NumIns();
buzbee67bf8852011-08-17 17:51:35 -07001764 for (int i = 0; i < inRegs; i++) {
1765 RegLocation loc = cUnit->regLocation[startLoc + i];
buzbeedfd3d702011-08-28 12:56:51 -07001766 //TUNING: be smarter about flushing ins to frame
1767 storeBaseDisp(cUnit, rSP, loc.spOffset, startReg + i, kWord);
buzbee67bf8852011-08-17 17:51:35 -07001768 if (loc.location == kLocPhysReg) {
1769 genRegCopy(cUnit, loc.lowReg, startReg + i);
buzbee67bf8852011-08-17 17:51:35 -07001770 }
1771 }
1772
1773 // Handle special case of wide argument half in regs, half in frame
1774 if (inRegs == 3) {
1775 RegLocation loc = cUnit->regLocation[startLoc + 2];
1776 if (loc.wide && loc.location == kLocPhysReg) {
1777 // Load the other half of the arg into the promoted pair
buzbee561227c2011-09-02 15:28:19 -07001778 loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
buzbee67bf8852011-08-17 17:51:35 -07001779 inRegs++;
1780 }
1781 }
1782
1783 // Now, do initial assignment of all promoted arguments passed in frame
Ian Rogers0cfe1fb2011-08-26 03:29:44 -07001784 for (int i = inRegs; i < cUnit->method->NumIns();) {
buzbee67bf8852011-08-17 17:51:35 -07001785 RegLocation loc = cUnit->regLocation[startLoc + i];
1786 if (loc.fpLocation == kLocPhysReg) {
1787 loc.location = kLocPhysReg;
1788 loc.fp = true;
1789 loc.lowReg = loc.fpLowReg;
1790 loc.highReg = loc.fpHighReg;
1791 }
1792 if (loc.location == kLocPhysReg) {
1793 if (loc.wide) {
1794 loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
1795 loc.lowReg, loc.highReg, INVALID_SREG);
1796 i++;
1797 } else {
buzbee561227c2011-09-02 15:28:19 -07001798 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
buzbee67bf8852011-08-17 17:51:35 -07001799 }
1800 }
1801 i++;
1802 }
1803}
1804
1805/* Handle the content in each basic block */
1806static bool methodBlockCodeGen(CompilationUnit* cUnit, BasicBlock* bb)
1807{
1808 MIR* mir;
1809 ArmLIR* labelList = (ArmLIR*) cUnit->blockLabelList;
1810 int blockId = bb->id;
1811
1812 cUnit->curBlock = bb;
1813 labelList[blockId].operands[0] = bb->startOffset;
1814
1815 /* Insert the block label */
1816 labelList[blockId].opcode = kArmPseudoNormalBlockLabel;
1817 oatAppendLIR(cUnit, (LIR*) &labelList[blockId]);
1818
1819 oatClobberAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001820
1821 ArmLIR* headLIR = NULL;
1822
1823 if (bb->blockType == kEntryBlock) {
1824 /*
1825 * On entry, r0, r1, r2 & r3 are live. Let the register allocation
1826 * mechanism know so it doesn't try to use any of them when
1827 * expanding the frame or flushing. This leaves the utility
1828 * code with a single temp: r12. This should be enough.
1829 */
1830 oatLockTemp(cUnit, r0);
1831 oatLockTemp(cUnit, r1);
1832 oatLockTemp(cUnit, r2);
1833 oatLockTemp(cUnit, r3);
buzbeecefd1872011-09-09 09:59:52 -07001834
1835 /*
1836 * We can safely skip the stack overflow check if we're
1837 * a leaf *and* our frame size < fudge factor.
1838 */
1839 bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
1840 ((size_t)cUnit->frameSize <
1841 art::Thread::kStackOverflowReservedBytes));
buzbee67bf8852011-08-17 17:51:35 -07001842 newLIR0(cUnit, kArmPseudoMethodEntry);
buzbeecefd1872011-09-09 09:59:52 -07001843 if (!skipOverflowCheck) {
1844 /* Load stack limit */
1845 loadWordDisp(cUnit, rSELF,
1846 art::Thread::StackEndOffset().Int32Value(), r12);
1847 }
buzbee67bf8852011-08-17 17:51:35 -07001848 /* Spill core callee saves */
1849 newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
1850 /* Need to spill any FP regs? */
1851 if (cUnit->numFPSpills) {
1852 newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
1853 }
buzbeecefd1872011-09-09 09:59:52 -07001854 if (!skipOverflowCheck) {
1855 opRegRegImm(cUnit, kOpSub, rLR, rSP,
1856 cUnit->frameSize - (cUnit->numSpills * 4));
buzbeeec5adf32011-09-11 15:25:43 -07001857 genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
1858 kArmThrowStackOverflow);
buzbeecefd1872011-09-09 09:59:52 -07001859 genRegCopy(cUnit, rSP, rLR); // Establish stack
1860 } else {
1861 opRegImm(cUnit, kOpSub, rSP,
1862 cUnit->frameSize - (cUnit->numSpills * 4));
1863 }
buzbee67bf8852011-08-17 17:51:35 -07001864 storeBaseDisp(cUnit, rSP, 0, r0, kWord);
1865 flushIns(cUnit);
1866 oatFreeTemp(cUnit, r0);
1867 oatFreeTemp(cUnit, r1);
1868 oatFreeTemp(cUnit, r2);
1869 oatFreeTemp(cUnit, r3);
1870 } else if (bb->blockType == kExitBlock) {
1871 newLIR0(cUnit, kArmPseudoMethodExit);
1872 opRegImm(cUnit, kOpAdd, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
1873 /* Need to restore any FP callee saves? */
1874 if (cUnit->numFPSpills) {
1875 newLIR1(cUnit, kThumb2VPopCS, cUnit->numFPSpills);
1876 }
1877 if (cUnit->coreSpillMask & (1 << rLR)) {
1878 /* Unspill rLR to rPC */
1879 cUnit->coreSpillMask &= ~(1 << rLR);
1880 cUnit->coreSpillMask |= (1 << rPC);
1881 }
1882 newLIR1(cUnit, kThumb2Pop, cUnit->coreSpillMask);
1883 if (!(cUnit->coreSpillMask & (1 << rPC))) {
1884 /* We didn't pop to rPC, so must do a bv rLR */
1885 newLIR1(cUnit, kThumbBx, rLR);
1886 }
1887 }
1888
1889 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1890
1891 oatResetRegPool(cUnit);
buzbeef0cde542011-09-13 14:55:02 -07001892 oatClobberAllRegs(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07001893
1894 if (cUnit->disableOpt & (1 << kSuppressLoads)) {
1895 oatResetDefTracking(cUnit);
1896 }
1897
1898 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
1899 handleExtendedMethodMIR(cUnit, mir);
1900 continue;
1901 }
1902
1903 cUnit->currentDalvikOffset = mir->offset;
1904
1905 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
1906 InstructionFormat dalvikFormat =
1907 dexGetFormatFromOpcode(dalvikOpcode);
1908
1909 ArmLIR* boundaryLIR;
1910
1911 /* Mark the beginning of a Dalvik instruction for line tracking */
1912 boundaryLIR = newLIR1(cUnit, kArmPseudoDalvikByteCodeBoundary,
1913 (int) oatGetDalvikDisassembly(
1914 &mir->dalvikInsn, ""));
1915 /* Remember the first LIR for this block */
1916 if (headLIR == NULL) {
1917 headLIR = boundaryLIR;
1918 /* Set the first boundaryLIR as a scheduling barrier */
1919 headLIR->defMask = ENCODE_ALL;
1920 }
1921
1922 /* Don't generate the SSA annotation unless verbose mode is on */
1923 if (cUnit->printMe && mir->ssaRep) {
1924 char *ssaString = oatGetSSAString(cUnit, mir->ssaRep);
1925 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
1926 }
1927
1928 bool notHandled = compileDalvikInstruction(cUnit, mir, bb, labelList);
1929
1930 if (notHandled) {
1931 char buf[100];
1932 snprintf(buf, 100, "%#06x: Opcode %#x (%s) / Fmt %d not handled",
1933 mir->offset,
1934 dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
1935 dalvikFormat);
1936 LOG(FATAL) << buf;
1937 }
1938 }
1939
1940 if (headLIR) {
1941 /*
1942 * Eliminate redundant loads/stores and delay stores into later
1943 * slots
1944 */
1945 oatApplyLocalOptimizations(cUnit, (LIR*) headLIR,
1946 cUnit->lastLIRInsn);
1947
1948 /*
1949 * Generate an unconditional branch to the fallthrough block.
1950 */
1951 if (bb->fallThrough) {
1952 genUnconditionalBranch(cUnit,
1953 &labelList[bb->fallThrough->id]);
1954 }
1955 }
1956 return false;
1957}
1958
1959/*
1960 * Nop any unconditional branches that go to the next instruction.
1961 * Note: new redundant branches may be inserted later, and we'll
1962 * use a check in final instruction assembly to nop those out.
1963 */
1964void removeRedundantBranches(CompilationUnit* cUnit)
1965{
1966 ArmLIR* thisLIR;
1967
1968 for (thisLIR = (ArmLIR*) cUnit->firstLIRInsn;
1969 thisLIR != (ArmLIR*) cUnit->lastLIRInsn;
1970 thisLIR = NEXT_LIR(thisLIR)) {
1971
1972 /* Branch to the next instruction */
1973 if ((thisLIR->opcode == kThumbBUncond) ||
1974 (thisLIR->opcode == kThumb2BUncond)) {
1975 ArmLIR* nextLIR = thisLIR;
1976
1977 while (true) {
1978 nextLIR = NEXT_LIR(nextLIR);
1979
1980 /*
1981 * Is the branch target the next instruction?
1982 */
1983 if (nextLIR == (ArmLIR*) thisLIR->generic.target) {
1984 thisLIR->flags.isNop = true;
1985 break;
1986 }
1987
1988 /*
1989 * Found real useful stuff between the branch and the target.
1990 * Need to explicitly check the lastLIRInsn here because it
1991 * might be the last real instruction.
1992 */
1993 if (!isPseudoOpcode(nextLIR->opcode) ||
1994 (nextLIR = (ArmLIR*) cUnit->lastLIRInsn))
1995 break;
1996 }
1997 }
1998 }
1999}
2000
buzbeec1f45042011-09-21 16:03:19 -07002001static void handleSuspendLaunchpads(CompilationUnit *cUnit)
2002{
2003 ArmLIR** suspendLabel =
2004 (ArmLIR **) cUnit->suspendLaunchpads.elemList;
2005 int numElems = cUnit->suspendLaunchpads.numUsed;
2006
2007 for (int i = 0; i < numElems; i++) {
2008 /* TUNING: move suspend count load into helper */
2009 ArmLIR* lab = suspendLabel[i];
2010 ArmLIR* resumeLab = (ArmLIR*)lab->operands[0];
2011 cUnit->currentDalvikOffset = lab->operands[1];
2012 oatAppendLIR(cUnit, (LIR *)lab);
2013 loadWordDisp(cUnit, rSELF,
2014 OFFSETOF_MEMBER(Thread, pTestSuspendFromCode), rLR);
2015 loadWordDisp(cUnit, rSELF,
2016 art::Thread::SuspendCountOffset().Int32Value(), rSUSPEND);
2017 opReg(cUnit, kOpBlx, rLR);
2018 genUnconditionalBranch(cUnit, resumeLab);
2019 }
2020}
2021
buzbee5ade1d22011-09-09 14:44:52 -07002022static void handleThrowLaunchpads(CompilationUnit *cUnit)
2023{
2024 ArmLIR** throwLabel =
2025 (ArmLIR **) cUnit->throwLaunchpads.elemList;
2026 int numElems = cUnit->throwLaunchpads.numUsed;
2027 int i;
2028
2029 for (i = 0; i < numElems; i++) {
2030 ArmLIR* lab = throwLabel[i];
2031 cUnit->currentDalvikOffset = lab->operands[1];
2032 oatAppendLIR(cUnit, (LIR *)lab);
2033 int funcOffset = 0;
2034 int v1 = lab->operands[2];
2035 int v2 = lab->operands[3];
2036 switch(lab->operands[0]) {
2037 case kArmThrowNullPointer:
2038 funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
2039 break;
2040 case kArmThrowArrayBounds:
2041 if (v2 != r0) {
2042 genRegCopy(cUnit, r0, v1);
2043 genRegCopy(cUnit, r1, v2);
2044 } else {
2045 if (v1 == r1) {
2046 genRegCopy(cUnit, r12, v1);
2047 genRegCopy(cUnit, r1, v2);
2048 genRegCopy(cUnit, r0, r12);
2049 } else {
2050 genRegCopy(cUnit, r1, v2);
2051 genRegCopy(cUnit, r0, v1);
2052 }
2053 }
2054 funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
2055 break;
2056 case kArmThrowDivZero:
2057 funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
2058 break;
2059 case kArmThrowVerificationError:
2060 loadConstant(cUnit, r0, v1);
2061 loadConstant(cUnit, r1, v2);
2062 funcOffset =
2063 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
2064 break;
2065 case kArmThrowNegArraySize:
2066 genRegCopy(cUnit, r0, v1);
2067 funcOffset =
2068 OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
2069 break;
2070 case kArmThrowInternalError:
2071 genRegCopy(cUnit, r0, v1);
2072 funcOffset =
2073 OFFSETOF_MEMBER(Thread, pThrowInternalErrorFromCode);
2074 break;
2075 case kArmThrowRuntimeException:
2076 genRegCopy(cUnit, r0, v1);
2077 funcOffset =
2078 OFFSETOF_MEMBER(Thread, pThrowRuntimeExceptionFromCode);
2079 break;
2080 case kArmThrowNoSuchMethod:
2081 genRegCopy(cUnit, r0, v1);
2082 funcOffset =
2083 OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
2084 break;
buzbeeec5adf32011-09-11 15:25:43 -07002085 case kArmThrowStackOverflow:
2086 funcOffset =
Ian Rogers932746a2011-09-22 18:57:50 -07002087 OFFSETOF_MEMBER(Thread, pThrowStackOverflowFromCode);
buzbeeec5adf32011-09-11 15:25:43 -07002088 // Restore stack alignment
2089 opRegImm(cUnit, kOpAdd, rSP, cUnit->numSpills * 4);
2090 break;
buzbee5ade1d22011-09-09 14:44:52 -07002091 default:
2092 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
2093 }
2094 loadWordDisp(cUnit, rSELF, funcOffset, rLR);
Ian Rogersff1ed472011-09-20 13:46:24 -07002095 callRuntimeHelper(cUnit, rLR);
buzbee5ade1d22011-09-09 14:44:52 -07002096 }
2097}
2098
buzbee67bf8852011-08-17 17:51:35 -07002099void oatMethodMIR2LIR(CompilationUnit* cUnit)
2100{
2101 /* Used to hold the labels of each block */
2102 cUnit->blockLabelList =
2103 (void *) oatNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
2104
2105 oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
2106 kPreOrderDFSTraversal, false /* Iterative */);
buzbeec1f45042011-09-21 16:03:19 -07002107 handleSuspendLaunchpads(cUnit);
buzbee5ade1d22011-09-09 14:44:52 -07002108
2109 handleThrowLaunchpads(cUnit);
buzbeec1f45042011-09-21 16:03:19 -07002110
2111 removeRedundantBranches(cUnit);
buzbee67bf8852011-08-17 17:51:35 -07002112}
2113
2114/* Common initialization routine for an architecture family */
2115bool oatArchInit()
2116{
2117 int i;
2118
2119 for (i = 0; i < kArmLast; i++) {
2120 if (EncodingMap[i].opcode != i) {
2121 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name <<
2122 " is wrong: expecting " << i << ", seeing " <<
2123 (int)EncodingMap[i].opcode;
2124 }
2125 }
2126
2127 return oatArchVariantInit();
2128}
2129
2130/* Needed by the Assembler */
2131void oatSetupResourceMasks(ArmLIR* lir)
2132{
2133 setupResourceMasks(lir);
2134}
2135
2136/* Needed by the ld/st optmizatons */
2137ArmLIR* oatRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
2138{
2139 return genRegCopyNoInsert(cUnit, rDest, rSrc);
2140}
2141
2142/* Needed by the register allocator */
2143ArmLIR* oatRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
2144{
2145 return genRegCopy(cUnit, rDest, rSrc);
2146}
2147
2148/* Needed by the register allocator */
2149void oatRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
2150 int srcLo, int srcHi)
2151{
2152 genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
2153}
2154
2155void oatFlushRegImpl(CompilationUnit* cUnit, int rBase,
2156 int displacement, int rSrc, OpSize size)
2157{
2158 storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
2159}
2160
2161void oatFlushRegWideImpl(CompilationUnit* cUnit, int rBase,
2162 int displacement, int rSrcLo, int rSrcHi)
2163{
2164 storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
2165}