blob: 1261e7d6a81b15020692f1d4baa169508d0b2ac1 [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
2 * Copyright (C) 2009 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
Bill Buzbee50a6bf22009-07-08 13:08:04 -070017/*
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
Ben Cheng4238ec22009-08-24 16:32:22 -070027#include "compiler/Loop.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070028
Ben Chengba4fc8b2009-06-01 13:00:29 -070029/* Array holding the entry offset of each template relative to the first one */
30static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
31
32/* Track exercised opcodes */
33static int opcodeCoverage[256];
34
Jeff Hao97319a82009-08-12 16:57:15 -070035#if defined(WITH_SELF_VERIFICATION)
36/* Prevent certain opcodes from being jitted */
37static inline bool selfVerificationPuntOps(OpCode op)
38{
39 return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT ||
40 op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY);
41}
42
43/*
44 * The following are used to keep compiled loads and stores from modifying
45 * memory during self verification mode.
46 *
47 * Stores do not modify memory. Instead, the address and value pair are stored
48 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
49 * than a word, the word containing the address is loaded first before being
50 * updated.
51 *
52 * Loads check heapSpace first and return data from there if an entry exists.
53 * Otherwise, data is loaded from memory as usual.
54 */
55
56/* Decode contents of heapArgSpace to determine addr to load from */
57static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
58{
Bill Buzbee1465db52009-09-23 17:17:35 -070059 int reg = heapArgSpace->regMap & 0xFF;
60 if (!FPREG(reg)) {
61 assert(reg < 16);
62 *addr = heapArgSpace->coreRegs[reg];
63 } else {
64 assert(!DOUBLEREG(reg));
65 *addr = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
Jeff Hao97319a82009-08-12 16:57:15 -070066 }
67}
68
69/* Decode contents of heapArgSpace to determine reg to load into */
70static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
71 int data, int reg)
72{
Bill Buzbee1465db52009-09-23 17:17:35 -070073 if (!FPREG(reg)) {
74 assert(reg < 16);
75 heapArgSpace->coreRegs[reg] = data;
76 } else {
77 assert(!DOUBLEREG(reg));
78 heapArgSpace->fpRegs[(reg & FP_REG_MASK)] = data;
Jeff Hao97319a82009-08-12 16:57:15 -070079 }
80}
81
82static void selfVerificationLoad(InterpState* interpState)
83{
84 Thread *self = dvmThreadSelf();
85 ShadowHeap *heapSpacePtr;
86 ShadowSpace *shadowSpace = self->shadowSpace;
87 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
88
89 int addr, data;
90 selfVerificationLoadDecode(heapArgSpace, &addr);
91
92 for (heapSpacePtr = shadowSpace->heapSpace;
93 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
94 if (heapSpacePtr->addr == addr) {
95 data = heapSpacePtr->data;
96 break;
97 }
98 }
99
100 if (heapSpacePtr == shadowSpace->heapSpaceTail)
101 data = *((unsigned int*) addr);
102
Bill Buzbee1465db52009-09-23 17:17:35 -0700103 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Ben Chengd7d426a2009-09-22 11:23:36 -0700104
Bill Buzbee1465db52009-09-23 17:17:35 -0700105 // LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
Ben Chengd7d426a2009-09-22 11:23:36 -0700106
Jeff Hao97319a82009-08-12 16:57:15 -0700107 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
108}
109
110static void selfVerificationLoadByte(InterpState* interpState)
111{
112 Thread *self = dvmThreadSelf();
113 ShadowHeap *heapSpacePtr;
114 ShadowSpace *shadowSpace = self->shadowSpace;
115 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
116
117 int addr, data;
118 selfVerificationLoadDecode(heapArgSpace, &addr);
119
120 int maskedAddr = addr & 0xFFFFFFFC;
121 int alignment = addr & 0x3;
122
123 for (heapSpacePtr = shadowSpace->heapSpace;
124 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
125 if (heapSpacePtr->addr == maskedAddr) {
126 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
127 data = *((unsigned char*) addr);
128 break;
129 }
130 }
131
132 if (heapSpacePtr == shadowSpace->heapSpaceTail)
133 data = *((unsigned char*) addr);
134
135 //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
136
Bill Buzbee1465db52009-09-23 17:17:35 -0700137 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700138 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
139}
140
141static void selfVerificationLoadHalfword(InterpState* interpState)
142{
143 Thread *self = dvmThreadSelf();
144 ShadowHeap *heapSpacePtr;
145 ShadowSpace *shadowSpace = self->shadowSpace;
146 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
147
148 int addr, data;
149 selfVerificationLoadDecode(heapArgSpace, &addr);
150
151 int maskedAddr = addr & 0xFFFFFFFC;
152 int alignment = addr & 0x2;
153
154 for (heapSpacePtr = shadowSpace->heapSpace;
155 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
156 if (heapSpacePtr->addr == maskedAddr) {
157 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
158 data = *((unsigned short*) addr);
159 break;
160 }
161 }
162
163 if (heapSpacePtr == shadowSpace->heapSpaceTail)
164 data = *((unsigned short*) addr);
165
Bill Buzbee1465db52009-09-23 17:17:35 -0700166 //LOGD("*** HEAP LOAD kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700167
Bill Buzbee1465db52009-09-23 17:17:35 -0700168 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700169 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
170}
171
172static void selfVerificationLoadSignedByte(InterpState* interpState)
173{
174 Thread *self = dvmThreadSelf();
175 ShadowHeap* heapSpacePtr;
176 ShadowSpace* shadowSpace = self->shadowSpace;
177 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
178
179 int addr, data;
180 selfVerificationLoadDecode(heapArgSpace, &addr);
181
182 int maskedAddr = addr & 0xFFFFFFFC;
183 int alignment = addr & 0x3;
184
185 for (heapSpacePtr = shadowSpace->heapSpace;
186 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
187 if (heapSpacePtr->addr == maskedAddr) {
188 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
189 data = *((signed char*) addr);
190 break;
191 }
192 }
193
194 if (heapSpacePtr == shadowSpace->heapSpaceTail)
195 data = *((signed char*) addr);
196
197 //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
198
Bill Buzbee1465db52009-09-23 17:17:35 -0700199 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700200 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
201}
202
203static void selfVerificationLoadSignedHalfword(InterpState* interpState)
204{
205 Thread *self = dvmThreadSelf();
206 ShadowHeap* heapSpacePtr;
207 ShadowSpace* shadowSpace = self->shadowSpace;
208 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
209
210 int addr, data;
211 selfVerificationLoadDecode(heapArgSpace, &addr);
212
213 int maskedAddr = addr & 0xFFFFFFFC;
214 int alignment = addr & 0x2;
215
216 for (heapSpacePtr = shadowSpace->heapSpace;
217 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
218 if (heapSpacePtr->addr == maskedAddr) {
219 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
220 data = *((signed short*) addr);
221 break;
222 }
223 }
224
225 if (heapSpacePtr == shadowSpace->heapSpaceTail)
226 data = *((signed short*) addr);
227
Bill Buzbee1465db52009-09-23 17:17:35 -0700228 //LOGD("*** HEAP LOAD SIGNED kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700229
Bill Buzbee1465db52009-09-23 17:17:35 -0700230 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700231 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
232}
233
234static void selfVerificationLoadDoubleword(InterpState* interpState)
235{
236 Thread *self = dvmThreadSelf();
237 ShadowHeap* heapSpacePtr;
238 ShadowSpace* shadowSpace = self->shadowSpace;
239 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
240
241 int addr;
242 selfVerificationLoadDecode(heapArgSpace, &addr);
243
244 int addr2 = addr+4;
245 unsigned int data = *((unsigned int*) addr);
246 unsigned int data2 = *((unsigned int*) addr2);
247
248 for (heapSpacePtr = shadowSpace->heapSpace;
249 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
250 if (heapSpacePtr->addr == addr) {
251 data = heapSpacePtr->data;
252 } else if (heapSpacePtr->addr == addr2) {
253 data2 = heapSpacePtr->data;
254 }
255 }
256
Bill Buzbee1465db52009-09-23 17:17:35 -0700257 // LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
Jeff Hao97319a82009-08-12 16:57:15 -0700258 // addr, data, data2);
259
Bill Buzbee1465db52009-09-23 17:17:35 -0700260 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
261 int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700262 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
263 selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
264}
265
266/* Decode contents of heapArgSpace to determine arguments to store. */
267static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
268 int* value, int reg)
269{
Bill Buzbee1465db52009-09-23 17:17:35 -0700270 if (!FPREG(reg)) {
271 assert(reg < 16);
272 *value = heapArgSpace->coreRegs[reg];
273 } else {
274 assert(!DOUBLEREG(reg));
275 *value = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
Jeff Hao97319a82009-08-12 16:57:15 -0700276 }
277}
278
279static void selfVerificationStore(InterpState* interpState)
280{
281 Thread *self = dvmThreadSelf();
282 ShadowHeap *heapSpacePtr;
283 ShadowSpace *shadowSpace = self->shadowSpace;
284 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
285
286 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700287 int reg0 = heapArgSpace->regMap & 0xFF;
288 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700289 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
290 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
291
292 //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
293
294 for (heapSpacePtr = shadowSpace->heapSpace;
295 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
296 if (heapSpacePtr->addr == addr) break;
297 }
298
299 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
300 heapSpacePtr->addr = addr;
301 shadowSpace->heapSpaceTail++;
302 }
303
304 heapSpacePtr->data = data;
305}
306
307static void selfVerificationStoreByte(InterpState* interpState)
308{
309 Thread *self = dvmThreadSelf();
310 ShadowHeap *heapSpacePtr;
311 ShadowSpace *shadowSpace = self->shadowSpace;
312 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
313
314 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700315 int reg0 = heapArgSpace->regMap & 0xFF;
316 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700317 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
318 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
319
320 int maskedAddr = addr & 0xFFFFFFFC;
321 int alignment = addr & 0x3;
322
323 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
324
325 for (heapSpacePtr = shadowSpace->heapSpace;
326 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
327 if (heapSpacePtr->addr == maskedAddr) break;
328 }
329
330 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
331 heapSpacePtr->addr = maskedAddr;
332 heapSpacePtr->data = *((unsigned int*) maskedAddr);
333 shadowSpace->heapSpaceTail++;
334 }
335
336 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
337 *((unsigned char*) addr) = (char) data;
338
339 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
340 // addr, heapSpacePtr->data);
341}
342
343static void selfVerificationStoreHalfword(InterpState* interpState)
344{
345 Thread *self = dvmThreadSelf();
346 ShadowHeap *heapSpacePtr;
347 ShadowSpace *shadowSpace = self->shadowSpace;
348 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
349
350 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700351 int reg0 = heapArgSpace->regMap & 0xFF;
352 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700353 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
354 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
355
356 int maskedAddr = addr & 0xFFFFFFFC;
357 int alignment = addr & 0x2;
358
Bill Buzbee1465db52009-09-23 17:17:35 -0700359 //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700360
361 for (heapSpacePtr = shadowSpace->heapSpace;
362 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
363 if (heapSpacePtr->addr == maskedAddr) break;
364 }
365
366 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
367 heapSpacePtr->addr = maskedAddr;
368 heapSpacePtr->data = *((unsigned int*) maskedAddr);
369 shadowSpace->heapSpaceTail++;
370 }
371
372 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
373 *((unsigned short*) addr) = (short) data;
374
Bill Buzbee1465db52009-09-23 17:17:35 -0700375 //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Final Data: 0x%x",
Jeff Hao97319a82009-08-12 16:57:15 -0700376 // addr, heapSpacePtr->data);
377}
378
379static void selfVerificationStoreDoubleword(InterpState* interpState)
380{
381 Thread *self = dvmThreadSelf();
382 ShadowHeap *heapSpacePtr;
383 ShadowSpace *shadowSpace = self->shadowSpace;
384 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
385
386 int addr, data, data2;
Bill Buzbee1465db52009-09-23 17:17:35 -0700387 int reg0 = heapArgSpace->regMap & 0xFF;
388 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
389 int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700390 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
391 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
392 selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
393
394 int addr2 = addr+4;
395 bool store1 = false, store2 = false;
396
397 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
398 // addr, data, data2);
399
400 for (heapSpacePtr = shadowSpace->heapSpace;
401 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
402 if (heapSpacePtr->addr == addr) {
403 heapSpacePtr->data = data;
404 store1 = true;
405 } else if (heapSpacePtr->addr == addr2) {
406 heapSpacePtr->data = data2;
407 store2 = true;
408 }
409 }
410
411 if (!store1) {
412 shadowSpace->heapSpaceTail->addr = addr;
413 shadowSpace->heapSpaceTail->data = data;
414 shadowSpace->heapSpaceTail++;
415 }
416 if (!store2) {
417 shadowSpace->heapSpaceTail->addr = addr2;
418 shadowSpace->heapSpaceTail->data = data2;
419 shadowSpace->heapSpaceTail++;
420 }
421}
422
423/* Common wrapper function for all memory operations */
424static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
425 void* funct)
426{
Bill Buzbee1465db52009-09-23 17:17:35 -0700427 /* push r0 and r7 to give us a foothold */
428 newLIR1(cUnit, kThumbPush, (1 << r0) | (1 << r7));
Jeff Hao97319a82009-08-12 16:57:15 -0700429
Bill Buzbee1465db52009-09-23 17:17:35 -0700430 /* Let the save handler know where the save record is */
431 loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace));
Jeff Hao97319a82009-08-12 16:57:15 -0700432
Bill Buzbee1465db52009-09-23 17:17:35 -0700433 /* Load the regMap and call the save handler [note: handler pops r0/r7] */
434 loadConstant(cUnit, r7, regMap);
435 genDispatchToHandler(cUnit, TEMPLATE_SAVE_STATE);
Jeff Hao97319a82009-08-12 16:57:15 -0700436
Bill Buzbee1465db52009-09-23 17:17:35 -0700437 /* Set function pointer, pass rGLUE and branch */
Jeff Hao97319a82009-08-12 16:57:15 -0700438 loadConstant(cUnit, r1, (int) funct);
Bill Buzbee1465db52009-09-23 17:17:35 -0700439 newLIR2(cUnit, kThumbMovRR, r0, rGLUE);
440 newLIR1(cUnit, kThumbBlxR, r1);
Jeff Hao97319a82009-08-12 16:57:15 -0700441
Bill Buzbee1465db52009-09-23 17:17:35 -0700442 /* Let the recover handler know where coreRegs[0] and restore regs */
443 loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace) +
444 offsetof(HeapArgSpace, coreRegs));
445 genDispatchToHandler(cUnit, TEMPLATE_RESTORE_STATE);
Jeff Hao97319a82009-08-12 16:57:15 -0700446}
447#endif
448
Ben Chengba4fc8b2009-06-01 13:00:29 -0700449/*
Bill Buzbee1465db52009-09-23 17:17:35 -0700450 * Load a Dalvik register into a physical register. Take care when
451 * using this routine, as it doesn't perform any bookkeeping regarding
452 * register liveness. That is the responsibility of the caller.
453 */
454static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
455 int reg1)
456{
457 rlSrc = updateLoc(cUnit, rlSrc); /* Is our value hiding in a live temp? */
458 if (rlSrc.location == kLocPhysReg) {
459 genRegCopy(cUnit, reg1, rlSrc.lowReg);
460 } else if (rlSrc.location == kLocRetval) {
461 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), reg1);
462 } else {
463 assert(rlSrc.location == kLocDalvikFrame);
464 loadWordDisp(cUnit, rFP, sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
465 reg1);
466 }
467}
468
469/*
470 * Similar to loadValueDirect, but clobbers and allocates the target
471 * register. Should be used when loading to a fixed register (for example,
472 * loading arguments to an out of line call.
473 */
474static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
475 int reg1)
476{
477 clobberReg(cUnit, reg1);
478 markRegInUse(cUnit, reg1);
479 loadValueDirect(cUnit, rlSrc, reg1);
480}
481
482/*
483 * Load a Dalvik register pair into a physical register[s]. Take care when
484 * using this routine, as it doesn't perform any bookkeeping regarding
485 * register liveness. That is the responsibility of the caller.
486 */
487static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
488 int regLo, int regHi)
489{
490 rlSrc = updateLocWide(cUnit, rlSrc);
491 if (rlSrc.location == kLocPhysReg) {
492 genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
493 } else if (rlSrc.location == kLocRetval) {
494 loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
495 regLo, regHi, false, INVALID_SREG);
496 } else {
497 assert(rlSrc.location == kLocDalvikFrame);
498 loadBaseDispWide(cUnit, NULL, rFP,
499 sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
500 regLo, regHi, false, INVALID_SREG);
501 }
502}
503
504/*
505 * Similar to loadValueDirect, but clobbers and allocates the target
506 * registers. Should be used when loading to a fixed registers (for example,
507 * loading arguments to an out of line call.
508 */
509static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
510 int regLo, int regHi)
511{
512 clobberReg(cUnit, regLo);
513 clobberReg(cUnit, regHi);
514 markRegInUse(cUnit, regLo);
515 markRegInUse(cUnit, regHi);
516 loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
517}
518
519static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
520 RegisterClass opKind)
521{
522 RegisterInfo *pReg;
523 rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
524 if (rlSrc.location == kLocDalvikFrame) {
525 loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
526 rlSrc.location = kLocPhysReg;
527 markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
528 } else if (rlSrc.location == kLocRetval) {
529 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg);
530 rlSrc.location = kLocPhysReg;
531 clobberReg(cUnit, rlSrc.lowReg);
532 }
533 return rlSrc;
534}
535
536static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
537 RegisterClass opKind)
538{
539 RegisterInfo *pRegLo;
540 RegisterInfo *pRegHi;
541 assert(rlSrc.wide);
542 rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
543 if (rlSrc.location == kLocDalvikFrame) {
544 loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
545 rlSrc.location = kLocPhysReg;
546 markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
547 markRegLive(cUnit, rlSrc.highReg, hiSReg(rlSrc.sRegLow));
548 } else if (rlSrc.location == kLocRetval) {
549 loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
550 rlSrc.lowReg, rlSrc.highReg, false, INVALID_SREG);
551 rlSrc.location = kLocPhysReg;
552 clobberReg(cUnit, rlSrc.lowReg);
553 clobberReg(cUnit, rlSrc.highReg);
554 }
555 return rlSrc;
556}
557
558static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
559 RegLocation rlSrc)
560{
561 RegisterInfo *pRegLo;
562 LIR *defStart;
563 LIR *defEnd;
564 assert(!rlDest.wide);
565 assert(!rlSrc.wide);
566 killNullCheckedLocation(cUnit, rlDest);
567 rlSrc = updateLoc(cUnit, rlSrc);
568 rlDest = updateLoc(cUnit, rlDest);
569 if (rlSrc.location == kLocPhysReg) {
570 if (isLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) {
571 // Src is live or Dest has assigned reg.
572 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
573 genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
574 } else {
575 // Just re-assign the registers. Dest gets Src's regs
576 rlDest.lowReg = rlSrc.lowReg;
577 clobberReg(cUnit, rlSrc.lowReg);
578 }
579 } else {
580 // Load Src either into promoted Dest or temps allocated for Dest
581 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
582 loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
583 }
584
585 // Dest is now live and dirty (until/if we flush it to home location)
586 markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
587 markRegDirty(cUnit, rlDest.lowReg);
588
589
590 if (rlDest.location == kLocRetval) {
591 storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
592 rlDest.lowReg, kWord);
593 clobberReg(cUnit, rlDest.lowReg);
594 } else {
595 resetDefLoc(cUnit, rlDest);
596 if (liveOut(cUnit, rlDest.sRegLow)) {
597 defStart = (LIR *)cUnit->lastLIRInsn;
598 int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
599 storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
600 markRegClean(cUnit, rlDest.lowReg);
601 defEnd = (LIR *)cUnit->lastLIRInsn;
602 markDef(cUnit, rlDest, defStart, defEnd);
603 }
604 }
605}
606
607static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
608 RegLocation rlSrc)
609{
610 RegisterInfo *pRegLo;
611 RegisterInfo *pRegHi;
612 LIR *defStart;
613 LIR *defEnd;
614 bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
615 assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
616 assert(rlDest.wide);
617 assert(rlSrc.wide);
618 killNullCheckedLocation(cUnit, rlDest);
619 if (rlSrc.location == kLocPhysReg) {
620 if (isLive(cUnit, rlSrc.lowReg) || isLive(cUnit, rlSrc.highReg) ||
621 (rlDest.location == kLocPhysReg)) {
622 // Src is live or Dest has assigned reg.
623 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
624 genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
625 rlSrc.lowReg, rlSrc.highReg);
626 } else {
627 // Just re-assign the registers. Dest gets Src's regs
628 rlDest.lowReg = rlSrc.lowReg;
629 rlDest.highReg = rlSrc.highReg;
630 clobberReg(cUnit, rlSrc.lowReg);
631 clobberReg(cUnit, rlSrc.highReg);
632 }
633 } else {
634 // Load Src either into promoted Dest or temps allocated for Dest
635 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
636 loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
637 rlDest.highReg);
638 }
639
640 // Dest is now live and dirty (until/if we flush it to home location)
641 markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
642 markRegLive(cUnit, rlDest.highReg, hiSReg(rlDest.sRegLow));
643 markRegDirty(cUnit, rlDest.lowReg);
644 markRegDirty(cUnit, rlDest.highReg);
645 markRegPair(cUnit, rlDest.lowReg, rlDest.highReg);
646
647
648 if (rlDest.location == kLocRetval) {
649 storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval),
650 rlDest.lowReg, rlDest.highReg);
651 clobberReg(cUnit, rlDest.lowReg);
652 clobberReg(cUnit, rlDest.highReg);
653 } else {
654 resetDefLocWide(cUnit, rlDest);
655 if (liveOut(cUnit, rlDest.sRegLow) ||
656 liveOut(cUnit, hiSReg(rlDest.sRegLow))) {
657 defStart = (LIR *)cUnit->lastLIRInsn;
658 int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
659 assert((vReg+1) == sReg2vReg(cUnit, hiSReg(rlDest.sRegLow)));
660 storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
661 rlDest.highReg);
662 markRegClean(cUnit, rlDest.lowReg);
663 markRegClean(cUnit, rlDest.highReg);
664 defEnd = (LIR *)cUnit->lastLIRInsn;
665 markDefWide(cUnit, rlDest, defStart, defEnd);
666 }
667 }
668}
669
670/*
671 * Load an immediate value into a fixed or temp register. Target
672 * register is clobbered, and marked inUse.
673 */
674static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
675{
676 if (isTemp(cUnit, rDest)) {
677 clobberReg(cUnit, rDest);
678 markRegInUse(cUnit, rDest);
679 }
680 return loadConstantValue(cUnit, rDest, value);
681}
682
683/*
Ben Chengd7d426a2009-09-22 11:23:36 -0700684 * Mark load/store instructions that access Dalvik registers through rFP +
685 * offset.
686 */
687static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
688{
689 if (isLoad) {
690 lir->useMask |= ENCODE_DALVIK_REG;
691 } else {
692 lir->defMask |= ENCODE_DALVIK_REG;
693 }
694
695 /*
696 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
697 * access.
698 */
699 lir->aliasInfo = regId;
700 if (DOUBLEREG(lir->operands[0])) {
701 lir->aliasInfo |= 0x80000000;
702 }
703}
704
705/*
706 * Decode the register id and mark the corresponding bit(s).
707 */
708static inline void setupRegMask(u8 *mask, int reg)
709{
710 u8 seed;
711 int shift;
712 int regId = reg & 0x1f;
713
714 /*
715 * Each double register is equal to a pair of single-precision FP registers
716 */
717 seed = DOUBLEREG(reg) ? 3 : 1;
718 /* FP register starts at bit position 16 */
719 shift = FPREG(reg) ? kFPReg0 : 0;
720 /* Expand the double register id into single offset */
721 shift += regId;
722 *mask |= seed << shift;
723}
724
725/*
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700726 * Set up the proper fields in the resource mask
727 */
728static void setupResourceMasks(ArmLIR *lir)
729{
730 int opCode = lir->opCode;
731 int flags;
732
733 if (opCode <= 0) {
734 lir->useMask = lir->defMask = 0;
735 return;
736 }
737
738 flags = EncodingMap[lir->opCode].flags;
739
740 /* Set up the mask for resources that are updated */
741 if (flags & IS_BRANCH) {
742 lir->defMask |= ENCODE_REG_PC;
Ben Chengd7d426a2009-09-22 11:23:36 -0700743 lir->useMask |= ENCODE_REG_PC;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700744 }
745
746 if (flags & REG_DEF0) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700747 setupRegMask(&lir->defMask, lir->operands[0]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700748 }
749
750 if (flags & REG_DEF1) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700751 setupRegMask(&lir->defMask, lir->operands[1]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700752 }
753
754 if (flags & REG_DEF_SP) {
755 lir->defMask |= ENCODE_REG_SP;
756 }
757
Ben Chengd7d426a2009-09-22 11:23:36 -0700758 if (flags & REG_DEF_SP) {
759 lir->defMask |= ENCODE_REG_LR;
760 }
761
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700762 if (flags & REG_DEF_LIST0) {
763 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
764 }
765
766 if (flags & REG_DEF_LIST1) {
767 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
768 }
769
770 if (flags & SETS_CCODES) {
771 lir->defMask |= ENCODE_CCODE;
772 }
773
774 /* Conservatively treat the IT block */
775 if (flags & IS_IT) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700776 lir->defMask = ENCODE_ALL;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700777 }
778
779 /* Set up the mask for resources that are used */
780 if (flags & IS_BRANCH) {
781 lir->useMask |= ENCODE_REG_PC;
782 }
783
Bill Buzbee1465db52009-09-23 17:17:35 -0700784 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700785 int i;
786
Bill Buzbee1465db52009-09-23 17:17:35 -0700787 for (i = 0; i < 4; i++) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700788 if (flags & (1 << (kRegUse0 + i))) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700789 setupRegMask(&lir->useMask, lir->operands[i]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700790 }
791 }
792 }
793
794 if (flags & REG_USE_PC) {
795 lir->useMask |= ENCODE_REG_PC;
796 }
797
798 if (flags & REG_USE_SP) {
799 lir->useMask |= ENCODE_REG_SP;
800 }
801
802 if (flags & REG_USE_LIST0) {
803 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
804 }
805
806 if (flags & REG_USE_LIST1) {
807 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
808 }
809
810 if (flags & USES_CCODES) {
811 lir->useMask |= ENCODE_CCODE;
812 }
813}
814
815/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700816 * The following are building blocks to construct low-level IRs with 0 - 4
Ben Chengba4fc8b2009-06-01 13:00:29 -0700817 * operands.
818 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700819static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700820{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700821 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700822 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700823 insn->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700824 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700825 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
826 return insn;
827}
828
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700829static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700830 int dest)
831{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700832 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700833 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700834 insn->opCode = opCode;
835 insn->operands[0] = dest;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700836 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700837 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
838 return insn;
839}
840
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700841static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700842 int dest, int src1)
843{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700844 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700845 assert(isPseudoOpCode(opCode) ||
846 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847 insn->opCode = opCode;
848 insn->operands[0] = dest;
849 insn->operands[1] = src1;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700850 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700851 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
852 return insn;
853}
854
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700855static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700856 int dest, int src1, int src2)
857{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700858 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700859 if (!(EncodingMap[opCode].flags & IS_TERTIARY_OP)) {
860 LOGE("Bad LIR3: %s[%d]",EncodingMap[opCode].name,opCode);
861 }
Ben Chenge9695e52009-06-16 16:11:47 -0700862 assert(isPseudoOpCode(opCode) ||
863 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700864 insn->opCode = opCode;
865 insn->operands[0] = dest;
866 insn->operands[1] = src1;
867 insn->operands[2] = src2;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700868 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700869 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
870 return insn;
871}
872
Bill Buzbee270c1d62009-08-13 16:58:07 -0700873static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
874 int dest, int src1, int src2, int info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700875{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700876 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
877 assert(isPseudoOpCode(opCode) ||
878 (EncodingMap[opCode].flags & IS_QUAD_OP));
879 insn->opCode = opCode;
880 insn->operands[0] = dest;
881 insn->operands[1] = src1;
882 insn->operands[2] = src2;
883 insn->operands[3] = info;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700884 setupResourceMasks(insn);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700885 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
886 return insn;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700887}
888
Ben Chengba4fc8b2009-06-01 13:00:29 -0700889/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700890 * If the next instruction is a move-result or move-result-long,
Bill Buzbee1465db52009-09-23 17:17:35 -0700891 * return the target Dalvik sReg[s] and convert the next to a
892 * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700893 */
Bill Buzbee1465db52009-09-23 17:17:35 -0700894static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
895 bool fpHint)
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700896{
897 if (mir->next &&
898 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
Bill Buzbee1465db52009-09-23 17:17:35 -0700899 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700900 mir->next->dalvikInsn.opCode = OP_NOP;
Bill Buzbee1465db52009-09-23 17:17:35 -0700901 return getDestLoc(cUnit, mir->next, 0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700902 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700903 RegLocation res = LOC_DALVIK_RETURN_VAL;
904 res.fp = fpHint;
905 return res;
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700906 }
907}
908
Bill Buzbee1465db52009-09-23 17:17:35 -0700909static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
910 bool fpHint)
911{
912 if (mir->next &&
913 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
914 mir->next->dalvikInsn.opCode = OP_NOP;
915 return getDestLocWide(cUnit, mir->next, 0, 1);
916 } else {
917 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
918 res.fp = fpHint;
919 return res;
920 }
921}
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700922
923/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700924 * The following are building blocks to insert constants into the pool or
925 * instruction streams.
926 */
927
928/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700929static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700930{
931 /* Add the constant to the literal pool */
932 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700933 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700934 newValue->operands[0] = value;
935 newValue->generic.next = cUnit->wordList;
936 cUnit->wordList = (LIR *) newValue;
937 return newValue;
938 } else {
939 /* Add the constant in the middle of code stream */
Bill Buzbee1465db52009-09-23 17:17:35 -0700940 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
941 newLIR1(cUnit, kArm16BitData, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700942 }
943 return NULL;
944}
945
946/*
947 * Search the existing constants in the literal pool for an exact or close match
948 * within specified delta (greater or equal to 0).
949 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700950static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700951 unsigned int delta)
952{
953 LIR *dataTarget = cUnit->wordList;
954 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700955 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700956 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700957 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700958 dataTarget = dataTarget->next;
959 }
960 return NULL;
961}
962
Ben Chengba4fc8b2009-06-01 13:00:29 -0700963/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700964static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
965 ArmLIR *branch,
966 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700967{
968 /* Set up the place holder to reconstruct this Dalvik PC */
969 if (pcrLabel == NULL) {
970 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700971 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700972 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700973 pcrLabel->operands[0] = dPC;
974 pcrLabel->operands[1] = dOffset;
975 /* Insert the place holder to the growable list */
976 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
977 }
978 /* Branch to the PC reconstruction code */
979 branch->generic.target = (LIR *) pcrLabel;
980 return pcrLabel;
981}
982
Ben Chengba4fc8b2009-06-01 13:00:29 -0700983
984/*
985 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
986 * satisfies.
987 */
Ben Cheng0fd31e42009-09-03 14:40:16 -0700988static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
989 ArmConditionCode cond,
990 int reg1, int reg2, int dOffset,
991 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700992{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700993 ArmLIR *res;
Bill Buzbee1465db52009-09-23 17:17:35 -0700994 res = opRegReg(cUnit, kOpCmp, reg1, reg2);
Ben Cheng4f489172009-09-27 17:08:35 -0700995 ArmLIR *branch = opCondBranch(cUnit, cond);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700996 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
997 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700998}
999
Ben Chenge9695e52009-06-16 16:11:47 -07001000/*
Bill Buzbee1465db52009-09-23 17:17:35 -07001001 * Perform null-check on a register. sReg is the ssa register being checked,
Ben Chenge9695e52009-06-16 16:11:47 -07001002 * and mReg is the machine register holding the actual value. If internal state
Bill Buzbee1465db52009-09-23 17:17:35 -07001003 * indicates that sReg has been checked before the check request is ignored.
Ben Chenge9695e52009-06-16 16:11:47 -07001004 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001005static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001006 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001007{
Ben Chenge9695e52009-06-16 16:11:47 -07001008 /* This particular Dalvik register has been null-checked */
Bill Buzbee1465db52009-09-23 17:17:35 -07001009 if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
Ben Chenge9695e52009-06-16 16:11:47 -07001010 return pcrLabel;
1011 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001012 dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
1013 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
Ben Chenge9695e52009-06-16 16:11:47 -07001014}
1015
1016/*
1017 * Perform zero-check on a register. Similar to genNullCheck but the value being
1018 * checked does not have a corresponding Dalvik register.
1019 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001020static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
1021 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -07001022{
Bill Buzbee1465db52009-09-23 17:17:35 -07001023 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001024}
1025
1026/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001027static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
1028 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001029{
Bill Buzbee1465db52009-09-23 17:17:35 -07001030 return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001031 pcrLabel);
1032}
1033
1034/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001035static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
1036 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001037{
Bill Buzbee1465db52009-09-23 17:17:35 -07001038 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001039 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
1040}
1041
1042/* Load a wide field from an object instance */
1043static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
1044{
1045 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001046 RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
1047 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
1048 RegLocation rlResult;
1049 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1050 int regPtr = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001051
Bill Buzbee1465db52009-09-23 17:17:35 -07001052 assert(rlDest.wide);
Ben Chenge9695e52009-06-16 16:11:47 -07001053
Bill Buzbee1465db52009-09-23 17:17:35 -07001054 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1055 NULL);/* null object? */
1056 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1057 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Jeff Hao97319a82009-08-12 16:57:15 -07001058#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001059 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07001060#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001061 int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001062 selfVerificationMemOpWrapper(cUnit, regMap,
1063 &selfVerificationLoadDoubleword);
Jeff Hao97319a82009-08-12 16:57:15 -07001064#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001065 freeTemp(cUnit, regPtr);
1066 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001067}
1068
1069/* Store a wide field to an object instance */
1070static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
1071{
1072 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001073 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1074 RegLocation rlObj = getSrcLoc(cUnit, mir, 2);
1075 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1076 int regPtr;
1077 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1078 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1079 NULL);/* null object? */
1080 regPtr = allocTemp(cUnit);
1081 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001082#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001083 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07001084#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001085 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001086 selfVerificationMemOpWrapper(cUnit, regMap,
1087 &selfVerificationStoreDoubleword);
1088#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001089 freeTemp(cUnit, regPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001090}
1091
1092/*
1093 * Load a field from an object instance
1094 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001095 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001096static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001097 int fieldOffset)
1098{
Bill Buzbee1465db52009-09-23 17:17:35 -07001099 int regPtr;
1100 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001101 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001102 RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
1103 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
1104 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1105 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Jeff Hao97319a82009-08-12 16:57:15 -07001106#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001107 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
1108 size, true, rlObj.sRegLow);
Jeff Hao97319a82009-08-12 16:57:15 -07001109#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001110 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1111 NULL);/* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -07001112 /* Combine address and offset */
Bill Buzbee1465db52009-09-23 17:17:35 -07001113 regPtr = allocTemp(cUnit);
1114 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001115
Bill Buzbee1465db52009-09-23 17:17:35 -07001116 int regMap = rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001117 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
Bill Buzbee1465db52009-09-23 17:17:35 -07001118 freeTemp(cUnit, regPtr);
Jeff Hao97319a82009-08-12 16:57:15 -07001119#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001120 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001121}
1122
1123/*
1124 * Store a field to an object instance
1125 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001126 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001127static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001128 int fieldOffset)
1129{
1130 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001131 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
1132 RegLocation rlObj = getSrcLoc(cUnit, mir, 1);
1133 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1134 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1135 int regPtr;
1136 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1137 NULL);/* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -07001138#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001139 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
Jeff Hao97319a82009-08-12 16:57:15 -07001140#else
1141 /* Combine address and offset */
Bill Buzbee1465db52009-09-23 17:17:35 -07001142 regPtr = allocTemp(cUnit);
1143 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001144
Bill Buzbee1465db52009-09-23 17:17:35 -07001145 int regMap = rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001146 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
Jeff Hao97319a82009-08-12 16:57:15 -07001147#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001148}
1149
1150
Ben Chengba4fc8b2009-06-01 13:00:29 -07001151/*
1152 * Generate array load
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001154static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Bill Buzbee1465db52009-09-23 17:17:35 -07001155 RegLocation rlArray, RegLocation rlIndex,
1156 RegLocation rlDest, int scale)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001157{
1158 int lenOffset = offsetof(ArrayObject, length);
1159 int dataOffset = offsetof(ArrayObject, contents);
Bill Buzbee1465db52009-09-23 17:17:35 -07001160 RegLocation rlResult;
1161 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1162 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1163 int regPtr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001164
1165 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001166 ArmLIR * pcrLabel = NULL;
1167
1168 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001169 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
1170 rlArray.lowReg, mir->offset, NULL);
Ben Cheng4238ec22009-08-24 16:32:22 -07001171 }
1172
Bill Buzbee1465db52009-09-23 17:17:35 -07001173 regPtr = allocTemp(cUnit);
1174
Ben Cheng4238ec22009-08-24 16:32:22 -07001175 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001176 int regLen = allocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07001177 /* Get len */
Bill Buzbee1465db52009-09-23 17:17:35 -07001178 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1179 /* regPtr -> array data */
1180 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1181 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
1182 pcrLabel);
1183 freeTemp(cUnit, regLen);
Ben Cheng4238ec22009-08-24 16:32:22 -07001184 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001185 /* regPtr -> array data */
1186 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -07001187 }
Jeff Hao97319a82009-08-12 16:57:15 -07001188#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001189 if ((size == kLong) || (size == kDouble)) {
1190 if (scale) {
1191 int rNewIndex = allocTemp(cUnit);
1192 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1193 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1194 freeTemp(cUnit, rNewIndex);
1195 } else {
1196 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1197 }
1198 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1199 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1200 freeTemp(cUnit, regPtr);
1201 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001202 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001203 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1204 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1205 scale, size);
1206 freeTemp(cUnit, regPtr);
1207 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001208 }
Jeff Hao97319a82009-08-12 16:57:15 -07001209#else
Bill Buzbee270c1d62009-08-13 16:58:07 -07001210 //TODO: probably want to move this into loadBaseIndexed
1211 void *funct = NULL;
1212 switch(size) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001213 case kLong:
1214 case kDouble:
Jeff Hao97319a82009-08-12 16:57:15 -07001215 funct = (void*) &selfVerificationLoadDoubleword;
1216 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001217 case kWord:
Jeff Hao97319a82009-08-12 16:57:15 -07001218 funct = (void*) &selfVerificationLoad;
1219 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001220 case kUnsignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001221 funct = (void*) &selfVerificationLoadHalfword;
1222 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001223 case kSignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001224 funct = (void*) &selfVerificationLoadSignedHalfword;
1225 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001226 case kUnsignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001227 funct = (void*) &selfVerificationLoadByte;
1228 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001229 case kSignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001230 funct = (void*) &selfVerificationLoadSignedByte;
1231 break;
1232 default:
1233 assert(0);
1234 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -07001235 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001236 /* Combine address and index */
Bill Buzbee1465db52009-09-23 17:17:35 -07001237 if (scale) {
1238 int regTmp = allocTemp(cUnit);
1239 opRegRegImm(cUnit, kOpLsl, regTmp, rlIndex.lowReg, scale);
1240 opRegReg(cUnit, kOpAdd, regPtr, regTmp);
1241 freeTemp(cUnit, regTmp);
1242 } else {
1243 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1244 }
Jeff Hao97319a82009-08-12 16:57:15 -07001245
Bill Buzbee1465db52009-09-23 17:17:35 -07001246 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1247 int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001248 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1249
Bill Buzbee1465db52009-09-23 17:17:35 -07001250 freeTemp(cUnit, regPtr);
1251 if ((size == kLong) || (size == kDouble))
1252 storeValueWide(cUnit, rlDest, rlResult);
Jeff Hao97319a82009-08-12 16:57:15 -07001253 else
Bill Buzbee1465db52009-09-23 17:17:35 -07001254 storeValue(cUnit, rlDest, rlResult);
Jeff Hao97319a82009-08-12 16:57:15 -07001255#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001256}
1257
Ben Chengba4fc8b2009-06-01 13:00:29 -07001258/*
1259 * Generate array store
1260 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001261 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001262static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Bill Buzbee1465db52009-09-23 17:17:35 -07001263 RegLocation rlArray, RegLocation rlIndex,
1264 RegLocation rlSrc, int scale)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001265{
1266 int lenOffset = offsetof(ArrayObject, length);
1267 int dataOffset = offsetof(ArrayObject, contents);
1268
Bill Buzbee1465db52009-09-23 17:17:35 -07001269 int regPtr;
1270 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1271 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001272
Bill Buzbee1465db52009-09-23 17:17:35 -07001273 if (isTemp(cUnit, rlArray.lowReg)) {
1274 clobberReg(cUnit, rlArray.lowReg);
1275 regPtr = rlArray.lowReg;
1276 } else {
1277 regPtr = allocTemp(cUnit);
1278 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1279 }
Ben Chenge9695e52009-06-16 16:11:47 -07001280
Ben Cheng1efc9c52009-06-08 18:25:27 -07001281 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001282 ArmLIR * pcrLabel = NULL;
1283
1284 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001285 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
1286 mir->offset, NULL);
Ben Cheng4238ec22009-08-24 16:32:22 -07001287 }
1288
1289 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001290 int regLen = allocTemp(cUnit);
1291 //NOTE: max live temps(4) here.
Ben Cheng4238ec22009-08-24 16:32:22 -07001292 /* Get len */
Bill Buzbee1465db52009-09-23 17:17:35 -07001293 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1294 /* regPtr -> array data */
1295 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1296 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
1297 pcrLabel);
1298 freeTemp(cUnit, regLen);
Ben Cheng4238ec22009-08-24 16:32:22 -07001299 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001300 /* regPtr -> array data */
1301 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -07001302 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001303 /* at this point, regPtr points to array, 2 live temps */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001304#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001305 if ((size == kLong) || (size == kDouble)) {
1306 //TODO: need specific wide routine that can handle fp regs
1307 if (scale) {
1308 int rNewIndex = allocTemp(cUnit);
1309 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1310 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1311 freeTemp(cUnit, rNewIndex);
1312 } else {
1313 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1314 }
1315 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1316 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1317 freeTemp(cUnit, regPtr);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001318 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001319 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1320 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1321 scale, size);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001322 }
1323#else
1324 //TODO: probably want to move this into storeBaseIndexed
1325 void *funct = NULL;
1326 switch(size) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001327 case kLong:
1328 case kDouble:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001329 funct = (void*) &selfVerificationStoreDoubleword;
1330 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001331 case kWord:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001332 funct = (void*) &selfVerificationStore;
1333 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001334 case kSignedHalf:
1335 case kUnsignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001336 funct = (void*) &selfVerificationStoreHalfword;
1337 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001338 case kSignedByte:
1339 case kUnsignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001340 funct = (void*) &selfVerificationStoreByte;
1341 break;
1342 default:
1343 assert(0);
1344 dvmAbort();
1345 }
1346
Bill Buzbee1465db52009-09-23 17:17:35 -07001347 if (scale) {
1348 int regTmpIndex = allocTemp(cUnit);
1349 // 3 live temps
1350 opRegRegImm(cUnit, kOpLsl, regTmpIndex, rlIndex.lowReg, scale);
1351 opRegReg(cUnit, kOpAdd, regPtr, regTmpIndex);
1352 freeTemp(cUnit, regTmpIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001353 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001354 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001355 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001356 /* Combine address and index */
1357 if ((size == kLong) || (size == kDouble)) {
1358 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1359 } else {
1360 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1361 }
Jeff Hao97319a82009-08-12 16:57:15 -07001362
Bill Buzbee1465db52009-09-23 17:17:35 -07001363 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001364 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1365
Jeff Hao97319a82009-08-12 16:57:15 -07001366#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001367}
1368
Bill Buzbee1465db52009-09-23 17:17:35 -07001369static bool handleShiftOpLong(CompilationUnit *cUnit, MIR *mir,
1370 RegLocation rlDest, RegLocation rlSrc1,
1371 RegLocation rlShift)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001372{
Ben Chenge9695e52009-06-16 16:11:47 -07001373 /*
1374 * Don't mess with the regsiters here as there is a particular calling
1375 * convention to the out-of-line handler.
1376 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001377 RegLocation rlResult;
1378
1379 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1380 loadValueDirect(cUnit, rlShift, r2);
Ben Chenge9695e52009-06-16 16:11:47 -07001381 switch( mir->dalvikInsn.opCode) {
1382 case OP_SHL_LONG:
1383 case OP_SHL_LONG_2ADDR:
1384 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1385 break;
1386 case OP_SHR_LONG:
1387 case OP_SHR_LONG_2ADDR:
1388 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1389 break;
1390 case OP_USHR_LONG:
1391 case OP_USHR_LONG_2ADDR:
1392 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1393 break;
1394 default:
1395 return true;
1396 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001397 rlResult = getReturnLocWide(cUnit);
1398 storeValueWide(cUnit, rlDest, rlResult);
Ben Chenge9695e52009-06-16 16:11:47 -07001399 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001400}
Bill Buzbee1465db52009-09-23 17:17:35 -07001401bool handleArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1402 RegLocation rlDest, RegLocation rlSrc1,
1403 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001404{
Bill Buzbee1465db52009-09-23 17:17:35 -07001405 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001406 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001407
Ben Chengba4fc8b2009-06-01 13:00:29 -07001408 /* TODO: use a proper include file to define these */
1409 float __aeabi_fadd(float a, float b);
1410 float __aeabi_fsub(float a, float b);
1411 float __aeabi_fdiv(float a, float b);
1412 float __aeabi_fmul(float a, float b);
1413 float fmodf(float a, float b);
1414
1415 switch (mir->dalvikInsn.opCode) {
1416 case OP_ADD_FLOAT_2ADDR:
1417 case OP_ADD_FLOAT:
1418 funct = (void*) __aeabi_fadd;
1419 break;
1420 case OP_SUB_FLOAT_2ADDR:
1421 case OP_SUB_FLOAT:
1422 funct = (void*) __aeabi_fsub;
1423 break;
1424 case OP_DIV_FLOAT_2ADDR:
1425 case OP_DIV_FLOAT:
1426 funct = (void*) __aeabi_fdiv;
1427 break;
1428 case OP_MUL_FLOAT_2ADDR:
1429 case OP_MUL_FLOAT:
1430 funct = (void*) __aeabi_fmul;
1431 break;
1432 case OP_REM_FLOAT_2ADDR:
1433 case OP_REM_FLOAT:
1434 funct = (void*) fmodf;
1435 break;
1436 case OP_NEG_FLOAT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001437 genNegFloat(cUnit, rlDest, rlSrc1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001438 return false;
1439 }
1440 default:
1441 return true;
1442 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001443 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001444 loadValueDirectFixed(cUnit, rlSrc1, r0);
1445 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001446 loadConstant(cUnit, r2, (int)funct);
Bill Buzbee1465db52009-09-23 17:17:35 -07001447 opReg(cUnit, kOpBlx, r2);
1448 clobberCallRegs(cUnit);
1449 rlResult = getReturnLoc(cUnit);
1450 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001451 return false;
1452}
1453
Bill Buzbee1465db52009-09-23 17:17:35 -07001454bool handleArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1455 RegLocation rlDest, RegLocation rlSrc1,
1456 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001457{
Bill Buzbee1465db52009-09-23 17:17:35 -07001458 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001459 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001460
Ben Chengba4fc8b2009-06-01 13:00:29 -07001461 /* TODO: use a proper include file to define these */
1462 double __aeabi_dadd(double a, double b);
1463 double __aeabi_dsub(double a, double b);
1464 double __aeabi_ddiv(double a, double b);
1465 double __aeabi_dmul(double a, double b);
1466 double fmod(double a, double b);
1467
1468 switch (mir->dalvikInsn.opCode) {
1469 case OP_ADD_DOUBLE_2ADDR:
1470 case OP_ADD_DOUBLE:
1471 funct = (void*) __aeabi_dadd;
1472 break;
1473 case OP_SUB_DOUBLE_2ADDR:
1474 case OP_SUB_DOUBLE:
1475 funct = (void*) __aeabi_dsub;
1476 break;
1477 case OP_DIV_DOUBLE_2ADDR:
1478 case OP_DIV_DOUBLE:
1479 funct = (void*) __aeabi_ddiv;
1480 break;
1481 case OP_MUL_DOUBLE_2ADDR:
1482 case OP_MUL_DOUBLE:
1483 funct = (void*) __aeabi_dmul;
1484 break;
1485 case OP_REM_DOUBLE_2ADDR:
1486 case OP_REM_DOUBLE:
1487 funct = (void*) fmod;
1488 break;
1489 case OP_NEG_DOUBLE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001490 genNegDouble(cUnit, rlDest, rlSrc1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001491 return false;
1492 }
1493 default:
1494 return true;
1495 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001496 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001497 loadConstant(cUnit, rlr, (int)funct);
1498 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1499 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1500 opReg(cUnit, kOpBlx, rlr);
1501 clobberCallRegs(cUnit);
1502 rlResult = getReturnLocWide(cUnit);
1503 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001504 return false;
1505}
1506
Bill Buzbee1465db52009-09-23 17:17:35 -07001507static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir,
1508 RegLocation rlDest, RegLocation rlSrc1,
1509 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001510{
Bill Buzbee1465db52009-09-23 17:17:35 -07001511 RegLocation rlResult;
1512 OpKind firstOp = kOpBkpt;
1513 OpKind secondOp = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001514 bool callOut = false;
1515 void *callTgt;
1516 int retReg = r0;
1517 /* TODO - find proper .h file to declare these */
1518 long long __aeabi_ldivmod(long long op1, long long op2);
1519
1520 switch (mir->dalvikInsn.opCode) {
1521 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07001522 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1523 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1524 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1525 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1526 storeValueWide(cUnit, rlDest, rlResult);
1527 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001528 break;
1529 case OP_ADD_LONG:
1530 case OP_ADD_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001531 firstOp = kOpAdd;
1532 secondOp = kOpAdc;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001533 break;
1534 case OP_SUB_LONG:
1535 case OP_SUB_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001536 firstOp = kOpSub;
1537 secondOp = kOpSbc;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001538 break;
1539 case OP_MUL_LONG:
1540 case OP_MUL_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001541 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001542 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001543 case OP_DIV_LONG:
1544 case OP_DIV_LONG_2ADDR:
1545 callOut = true;
1546 retReg = r0;
1547 callTgt = (void*)__aeabi_ldivmod;
1548 break;
1549 /* NOTE - result is in r2/r3 instead of r0/r1 */
1550 case OP_REM_LONG:
1551 case OP_REM_LONG_2ADDR:
1552 callOut = true;
1553 callTgt = (void*)__aeabi_ldivmod;
1554 retReg = r2;
1555 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001556 case OP_AND_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001557 case OP_AND_LONG:
1558 firstOp = kOpAnd;
1559 secondOp = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001560 break;
1561 case OP_OR_LONG:
1562 case OP_OR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001563 firstOp = kOpOr;
1564 secondOp = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001565 break;
1566 case OP_XOR_LONG:
1567 case OP_XOR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001568 firstOp = kOpXor;
1569 secondOp = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001570 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001571 case OP_NEG_LONG: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001572 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1573 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1574 loadConstantValue(cUnit, rlResult.highReg, 0);
1575 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1576 rlResult.highReg, rlSrc2.lowReg);
1577 opRegReg(cUnit, kOpSbc, rlResult.highReg, rlSrc2.highReg);
1578 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001579 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001580 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001581 default:
1582 LOGE("Invalid long arith op");
1583 dvmAbort();
1584 }
1585 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001586 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001587 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001588 // Adjust return regs in to handle case of rem returning r2/r3
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001589 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001590 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1591 loadConstant(cUnit, rlr, (int) callTgt);
1592 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1593 opReg(cUnit, kOpBlx, rlr);
1594 clobberCallRegs(cUnit);
1595 if (retReg == r0)
1596 rlResult = getReturnLocWide(cUnit);
1597 else
1598 rlResult = getReturnLocWideAlt(cUnit);
1599 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001600 }
1601 return false;
1602}
1603
Bill Buzbee1465db52009-09-23 17:17:35 -07001604static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir,
1605 RegLocation rlDest, RegLocation rlSrc1,
1606 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001607{
Bill Buzbee1465db52009-09-23 17:17:35 -07001608 OpKind op = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001609 bool callOut = false;
1610 bool checkZero = false;
Bill Buzbee1465db52009-09-23 17:17:35 -07001611 bool unary = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001612 int retReg = r0;
1613 void *callTgt;
Bill Buzbee1465db52009-09-23 17:17:35 -07001614 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001615
1616 /* TODO - find proper .h file to declare these */
1617 int __aeabi_idivmod(int op1, int op2);
1618 int __aeabi_idiv(int op1, int op2);
1619
1620 switch (mir->dalvikInsn.opCode) {
1621 case OP_NEG_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001622 op = kOpNeg;
1623 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001624 break;
1625 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001626 op = kOpMvn;
1627 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001628 break;
1629 case OP_ADD_INT:
1630 case OP_ADD_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001631 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001632 break;
1633 case OP_SUB_INT:
1634 case OP_SUB_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001635 op = kOpSub;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001636 break;
1637 case OP_MUL_INT:
1638 case OP_MUL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001639 op = kOpMul;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001640 break;
1641 case OP_DIV_INT:
1642 case OP_DIV_INT_2ADDR:
1643 callOut = true;
1644 checkZero = true;
1645 callTgt = __aeabi_idiv;
1646 retReg = r0;
1647 break;
1648 /* NOTE: returns in r1 */
1649 case OP_REM_INT:
1650 case OP_REM_INT_2ADDR:
1651 callOut = true;
1652 checkZero = true;
1653 callTgt = __aeabi_idivmod;
1654 retReg = r1;
1655 break;
1656 case OP_AND_INT:
1657 case OP_AND_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001658 op = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001659 break;
1660 case OP_OR_INT:
1661 case OP_OR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001662 op = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001663 break;
1664 case OP_XOR_INT:
1665 case OP_XOR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001666 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001667 break;
1668 case OP_SHL_INT:
1669 case OP_SHL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001670 op = kOpLsl;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001671 break;
1672 case OP_SHR_INT:
1673 case OP_SHR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001674 op = kOpAsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001675 break;
1676 case OP_USHR_INT:
1677 case OP_USHR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001678 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001679 break;
1680 default:
1681 LOGE("Invalid word arith op: 0x%x(%d)",
1682 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1683 dvmAbort();
1684 }
1685 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001686 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1687 if (unary) {
1688 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1689 opRegReg(cUnit, op, rlResult.lowReg,
1690 rlSrc1.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001691 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001692 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1693 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1694 opRegRegReg(cUnit, op, rlResult.lowReg,
1695 rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001696 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001697 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001698 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001699 RegLocation rlResult;
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001700 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001701 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001702 loadConstant(cUnit, r2, (int) callTgt);
Bill Buzbee1465db52009-09-23 17:17:35 -07001703 loadValueDirectFixed(cUnit, rlSrc1, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001704 if (checkZero) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001705 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001706 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001707 opReg(cUnit, kOpBlx, r2);
1708 clobberCallRegs(cUnit);
1709 if (retReg == r0)
1710 rlResult = getReturnLoc(cUnit);
1711 else
1712 rlResult = getReturnLocAlt(cUnit);
1713 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001714 }
1715 return false;
1716}
1717
Bill Buzbee1465db52009-09-23 17:17:35 -07001718static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001719{
1720 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001721 RegLocation rlDest;
1722 RegLocation rlSrc1;
1723 RegLocation rlSrc2;
1724 /* Deduce sizes of operands */
1725 if (mir->ssaRep->numUses == 2) {
1726 rlSrc1 = getSrcLoc(cUnit, mir, 0);
1727 rlSrc2 = getSrcLoc(cUnit, mir, 1);
1728 } else if (mir->ssaRep->numUses == 3) {
1729 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1730 rlSrc2 = getSrcLoc(cUnit, mir, 2);
1731 } else {
1732 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1733 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
1734 assert(mir->ssaRep->numUses == 4);
1735 }
1736 if (mir->ssaRep->numDefs == 1) {
1737 rlDest = getDestLoc(cUnit, mir, 0);
1738 } else {
1739 assert(mir->ssaRep->numDefs == 2);
1740 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1741 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001742
1743 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001744 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001745 }
1746 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001747 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001748 }
1749 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001750 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001751 }
1752 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001753 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001754 }
1755 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001756 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001757 }
1758 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001759 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001760 }
1761 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001762 return handleArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001763 }
1764 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001765 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001766 }
1767 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001768 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001769 }
1770 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001771 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001772 }
1773 return true;
1774}
1775
Bill Buzbee1465db52009-09-23 17:17:35 -07001776/* Generate conditional branch instructions */
1777static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1778 ArmConditionCode cond,
1779 ArmLIR *target)
1780{
1781 ArmLIR *branch = opCondBranch(cUnit, cond);
1782 branch->generic.target = (LIR *) target;
1783 return branch;
1784}
1785
1786/* Generate unconditional branch instructions */
1787static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1788{
1789 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
1790 branch->generic.target = (LIR *) target;
1791 return branch;
1792}
1793
1794/*
1795 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
1796 * blocks.
1797 */
1798static void genBarrier(CompilationUnit *cUnit)
1799{
1800 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
1801 /* Mark all resources as being clobbered */
1802 barrier->defMask = -1;
1803}
1804
1805/* Perform the actual operation for OP_RETURN_* */
1806static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
1807{
1808 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
1809#if defined(INVOKE_STATS)
1810 gDvmJit.returnOp++;
1811#endif
1812 int dPC = (int) (cUnit->method->insns + mir->offset);
1813 /* Insert branch, but defer setting of target */
1814 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
1815 /* Set up the place holder to reconstruct this Dalvik PC */
1816 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1817 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
1818 pcrLabel->operands[0] = dPC;
1819 pcrLabel->operands[1] = mir->offset;
1820 /* Insert the place holder to the growable list */
1821 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1822 /* Branch to the PC reconstruction code */
1823 branch->generic.target = (LIR *) pcrLabel;
1824}
1825
Bill Buzbeed45ba372009-06-15 17:00:57 -07001826static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1827 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001828{
Ben Chenge9695e52009-06-16 16:11:47 -07001829 /*
1830 * Don't optimize the register usage since it calls out to template
1831 * functions
1832 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001833 RegLocation rlSrc;
1834 RegLocation rlDest;
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001835 flushAllRegs(cUnit); /* Send everything to home location */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001836 if (srcSize == 1) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001837 rlSrc = getSrcLoc(cUnit, mir, 0);
1838 loadValueDirectFixed(cUnit, rlSrc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001839 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001840 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1841 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001842 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001843 loadConstant(cUnit, r2, (int)funct);
1844 opReg(cUnit, kOpBlx, r2);
1845 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001846 if (tgtSize == 1) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001847 RegLocation rlResult;
1848 rlDest = getDestLoc(cUnit, mir, 0);
1849 rlResult = getReturnLoc(cUnit);
1850 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001851 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001852 RegLocation rlResult;
1853 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1854 rlResult = getReturnLocWide(cUnit);
1855 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001856 }
1857 return false;
1858}
1859
Ben Chengba4fc8b2009-06-01 13:00:29 -07001860static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1861 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001862 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001863{
1864 unsigned int i;
1865 unsigned int regMask = 0;
Bill Buzbee1465db52009-09-23 17:17:35 -07001866 RegLocation rlArg;
1867 int numDone = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001868
Bill Buzbee1465db52009-09-23 17:17:35 -07001869 /*
1870 * Load arguments to r0..r4. Note that these registers may contain
1871 * live values, so we clobber them immediately after loading to prevent
1872 * them from being used as sources for subsequent loads.
1873 */
1874 lockAllTemps(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001875 for (i = 0; i < dInsn->vA; i++) {
1876 regMask |= 1 << i;
Bill Buzbee1465db52009-09-23 17:17:35 -07001877 rlArg = getSrcLoc(cUnit, mir, numDone++);
1878 loadValueDirectFixed(cUnit, rlArg, i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001879 }
1880 if (regMask) {
1881 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee1465db52009-09-23 17:17:35 -07001882 opRegRegImm(cUnit, kOpSub, r7, rFP,
1883 sizeof(StackSaveArea) + (dInsn->vA << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001884 /* generate null check */
1885 if (pcrLabel) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001886 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1887 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001888 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001889 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001890 }
1891}
1892
1893static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1894 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001895 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001896{
1897 int srcOffset = dInsn->vC << 2;
1898 int numArgs = dInsn->vA;
1899 int regMask;
Bill Buzbee1465db52009-09-23 17:17:35 -07001900
1901 /*
1902 * Note: here, all promoted registers will have been flushed
1903 * back to the Dalvik base locations, so register usage restrictins
1904 * are lifted. All parms loaded from original Dalvik register
1905 * region - even though some might conceivably have valid copies
1906 * cached in a preserved register.
1907 */
1908 lockAllTemps(cUnit);
1909
Ben Chengba4fc8b2009-06-01 13:00:29 -07001910 /*
1911 * r4PC : &rFP[vC]
1912 * r7: &newFP[0]
1913 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001914 opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001915 /* load [r0 .. min(numArgs,4)] */
1916 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001917 /*
1918 * Protect the loadMultiple instruction from being reordered with other
1919 * Dalvik stack accesses.
1920 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001921 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001922
Bill Buzbee1465db52009-09-23 17:17:35 -07001923 opRegRegImm(cUnit, kOpSub, r7, rFP,
1924 sizeof(StackSaveArea) + (numArgs << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001925 /* generate null check */
1926 if (pcrLabel) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001927 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1928 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001929 }
1930
1931 /*
1932 * Handle remaining 4n arguments:
1933 * store previously loaded 4 values and load the next 4 values
1934 */
1935 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001936 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001937 /*
1938 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001939 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001940 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001941 opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001942 /* No need to generate the loop structure if numArgs <= 11 */
1943 if (numArgs > 11) {
1944 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee1465db52009-09-23 17:17:35 -07001945 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07001946 loopLabel->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001947 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001948 storeMultiple(cUnit, r7, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001949 /*
1950 * Protect the loadMultiple instruction from being reordered with other
1951 * Dalvik stack accesses.
1952 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001953 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001954 /* No need to generate the loop structure if numArgs <= 11 */
1955 if (numArgs > 11) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001956 opRegImm(cUnit, kOpSub, rFP, 4);
1957 genConditionalBranch(cUnit, kArmCondNe, loopLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001958 }
1959 }
1960
1961 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001962 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001963
1964 /* Generate the loop epilogue - don't use r0 */
1965 if ((numArgs > 4) && (numArgs % 4)) {
1966 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001967 /*
1968 * Protect the loadMultiple instruction from being reordered with other
1969 * Dalvik stack accesses.
1970 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001971 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001972 }
1973 if (numArgs >= 8)
Bill Buzbee1465db52009-09-23 17:17:35 -07001974 opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001975
1976 /* Save the modulo 4 arguments */
1977 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001978 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001979 }
1980}
1981
Ben Cheng38329f52009-07-07 14:19:20 -07001982/*
1983 * Generate code to setup the call stack then jump to the chaining cell if it
1984 * is not a native method.
1985 */
1986static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001987 BasicBlock *bb, ArmLIR *labelList,
1988 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001989 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001990{
Bill Buzbee1465db52009-09-23 17:17:35 -07001991 /*
1992 * Note: all Dalvik register state should be flushed to
1993 * memory by the point, so register usage restrictions no
1994 * longer apply. All temp & preserved registers may be used.
1995 */
1996 lockAllTemps(cUnit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001997 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001998
1999 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002000 lockTemp(cUnit, r1);
2001 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002002 /* r4PC = dalvikCallsite */
2003 loadConstant(cUnit, r4PC,
2004 (int) (cUnit->method->insns + mir->offset));
2005 addrRetChain->generic.target = (LIR *) retChainingCell;
2006 /*
Ben Cheng38329f52009-07-07 14:19:20 -07002007 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002008 * r1 = &ChainingCell
2009 * r4PC = callsiteDPC
2010 */
2011 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07002012 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002013#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07002014 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002015#endif
2016 } else {
2017 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
2018#if defined(INVOKE_STATS)
2019 gDvmJit.invokeChain++;
2020#endif
Ben Cheng38329f52009-07-07 14:19:20 -07002021 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002022 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2023 }
2024 /* Handle exceptions using the interpreter */
2025 genTrap(cUnit, mir->offset, pcrLabel);
2026}
2027
Ben Cheng38329f52009-07-07 14:19:20 -07002028/*
2029 * Generate code to check the validity of a predicted chain and take actions
2030 * based on the result.
2031 *
2032 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
2033 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
2034 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
2035 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
2036 * 0x426a99b2 : blx_2 see above --+
2037 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
2038 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
2039 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
2040 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
2041 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
2042 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
2043 * 0x426a99c0 : blx r7 --+
2044 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
2045 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2046 * 0x426a99c6 : blx_2 see above --+
2047 */
2048static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
2049 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002050 ArmLIR *retChainingCell,
2051 ArmLIR *predChainingCell,
2052 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07002053{
Bill Buzbee1465db52009-09-23 17:17:35 -07002054 /*
2055 * Note: all Dalvik register state should be flushed to
2056 * memory by the point, so register usage restrictions no
2057 * longer apply. Lock temps to prevent them from being
2058 * allocated by utility routines.
2059 */
2060 lockAllTemps(cUnit);
2061
Ben Cheng38329f52009-07-07 14:19:20 -07002062 /* "this" is already left in r0 by genProcessArgs* */
2063
2064 /* r4PC = dalvikCallsite */
2065 loadConstant(cUnit, r4PC,
2066 (int) (cUnit->method->insns + mir->offset));
2067
2068 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002069 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002070 addrRetChain->generic.target = (LIR *) retChainingCell;
2071
2072 /* r2 = &predictedChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002073 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002074 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2075
2076 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2077
2078 /* return through lr - jump to the chaining cell */
2079 genUnconditionalBranch(cUnit, predChainingCell);
2080
2081 /*
2082 * null-check on "this" may have been eliminated, but we still need a PC-
2083 * reconstruction label for stack overflow bailout.
2084 */
2085 if (pcrLabel == NULL) {
2086 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002087 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07002088 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07002089 pcrLabel->operands[0] = dPC;
2090 pcrLabel->operands[1] = mir->offset;
2091 /* Insert the place holder to the growable list */
2092 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2093 }
2094
2095 /* return through lr+2 - punt to the interpreter */
2096 genUnconditionalBranch(cUnit, pcrLabel);
2097
2098 /*
2099 * return through lr+4 - fully resolve the callee method.
2100 * r1 <- count
2101 * r2 <- &predictedChainCell
2102 * r3 <- this->class
2103 * r4 <- dPC
2104 * r7 <- this->class->vtable
2105 */
2106
2107 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002108 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07002109
2110 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07002111 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002112
Bill Buzbee1465db52009-09-23 17:17:35 -07002113 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07002114
Bill Buzbee270c1d62009-08-13 16:58:07 -07002115 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2116 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002117
2118 /*
2119 * r0 = calleeMethod
2120 * r2 = &predictedChainingCell
2121 * r3 = class
2122 *
2123 * &returnChainingCell has been loaded into r1 but is not needed
2124 * when patching the chaining cell and will be clobbered upon
2125 * returning so it will be reconstructed again.
2126 */
Bill Buzbee1465db52009-09-23 17:17:35 -07002127 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002128
2129 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002130 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002131 addrRetChain->generic.target = (LIR *) retChainingCell;
2132
2133 bypassRechaining->generic.target = (LIR *) addrRetChain;
2134 /*
2135 * r0 = calleeMethod,
2136 * r1 = &ChainingCell,
2137 * r4PC = callsiteDPC,
2138 */
2139 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2140#if defined(INVOKE_STATS)
2141 gDvmJit.invokePredictedChain++;
2142#endif
2143 /* Handle exceptions using the interpreter */
2144 genTrap(cUnit, mir->offset, pcrLabel);
2145}
2146
2147/*
2148 * Up calling this function, "this" is stored in r0. The actual class will be
2149 * chased down off r0 and the predicted one will be retrieved through
2150 * predictedChainingCell then a comparison is performed to see whether the
2151 * previously established chaining is still valid.
2152 *
2153 * The return LIR is a branch based on the comparison result. The actual branch
2154 * target will be setup in the caller.
2155 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002156static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
2157 ArmLIR *predChainingCell,
2158 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07002159 MIR *mir)
2160{
Bill Buzbee1465db52009-09-23 17:17:35 -07002161 /*
2162 * Note: all Dalvik register state should be flushed to
2163 * memory by the point, so register usage restrictions no
2164 * longer apply. All temp & preserved registers may be used.
2165 */
2166 lockAllTemps(cUnit);
2167
Ben Cheng38329f52009-07-07 14:19:20 -07002168 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002169 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002170
2171 /*
2172 * r2 now contains predicted class. The starting offset of the
2173 * cached value is 4 bytes into the chaining cell.
2174 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002175 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002176 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07002177 getPredictedClass->generic.target = (LIR *) predChainingCell;
2178
2179 /*
2180 * r0 now contains predicted method. The starting offset of the
2181 * cached value is 8 bytes into the chaining cell.
2182 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002183 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002184 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07002185 getPredictedMethod->generic.target = (LIR *) predChainingCell;
2186
2187 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002188 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002189 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002190 getRechainingRequestCount->generic.target =
2191 (LIR *) predChainingCell;
2192
2193 /* r4PC = dalvikCallsite */
2194 loadConstant(cUnit, r4PC,
2195 (int) (cUnit->method->insns + mir->offset));
2196
2197 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002198 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002199 addrRetChain->generic.target = (LIR *) retChainingCell;
2200
2201 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee1465db52009-09-23 17:17:35 -07002202 opRegReg(cUnit, kOpCmp, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002203
Bill Buzbee1465db52009-09-23 17:17:35 -07002204 return opCondBranch(cUnit, kArmCondEq);
Ben Cheng38329f52009-07-07 14:19:20 -07002205}
2206
Ben Chengba4fc8b2009-06-01 13:00:29 -07002207/* Geneate a branch to go back to the interpreter */
2208static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
2209{
2210 /* r0 = dalvik pc */
Bill Buzbee1465db52009-09-23 17:17:35 -07002211 flushAllRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002212 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002213 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
2214 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2215 jitToInterpEntries.dvmJitToInterpPunt), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002216 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002217}
2218
2219/*
2220 * Attempt to single step one instruction using the interpreter and return
2221 * to the compiled code for the next Dalvik instruction
2222 */
2223static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
2224{
2225 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
2226 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
2227 kInstrCanThrow;
Bill Buzbee1465db52009-09-23 17:17:35 -07002228
2229 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
2230 flushAllRegs(cUnit);
2231
Ben Chengba4fc8b2009-06-01 13:00:29 -07002232 if ((mir->next == NULL) || (flags & flagsToCheck)) {
2233 genPuntToInterp(cUnit, mir->offset);
2234 return;
2235 }
2236 int entryAddr = offsetof(InterpState,
2237 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002238 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002239 /* r0 = dalvik pc */
2240 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
2241 /* r1 = dalvik pc of following instruction */
2242 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -07002243 opReg(cUnit, kOpBlx, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002244}
2245
Bill Buzbee1465db52009-09-23 17:17:35 -07002246static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002247{
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08002248 bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002249 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002250 genExportPC(cUnit, mir);
2251 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2252 loadValueDirectFixed(cUnit, rlSrc, r1);
2253 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08002254 if (isEnter) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002255 loadConstant(cUnit, r2, (int)dvmLockObject);
2256 } else {
2257 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2258 }
2259 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
2260 /* Do the call */
2261 opReg(cUnit, kOpBlx, r2);
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08002262#if defined(WITH_DEADLOCK_PREDICTION)
2263 if (isEnter) {
2264 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
2265 loadWordDisp(cUnit, r0, offsetof(Thread, exception), r1);
2266 opRegImm(cUnit, kOpCmp, r1, 0);
2267 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondEq);
2268 loadConstant(cUnit, r0,
2269 (int) (cUnit->method->insns + mir->offset));
2270 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2271 /* noreturn */
2272 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2273 target->defMask = ENCODE_ALL;
2274 branchOver->generic.target = (LIR *) target;
2275 }
2276#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002277 clobberCallRegs(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002278}
2279
2280/* Load a word at base + displacement. Displacement must be word multiple */
2281static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
2282 int rDest)
2283{
Bill Buzbee1465db52009-09-23 17:17:35 -07002284 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, false,
2285 INVALID_SREG);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002286}
2287
2288static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
Bill Buzbee1465db52009-09-23 17:17:35 -07002289 int displacement, int rSrc)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002290{
Bill Buzbee1465db52009-09-23 17:17:35 -07002291 return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002292}
2293
2294static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
2295{
2296 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
2297 dvmCompilerAppendLIR(cUnit, (LIR*)res);
2298 return res;
2299}
2300
Ben Chengba4fc8b2009-06-01 13:00:29 -07002301/*
2302 * The following are the first-level codegen routines that analyze the format
2303 * of each bytecode then either dispatch special purpose codegen routines
2304 * or produce corresponding Thumb instructions directly.
2305 */
2306
2307static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002308 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002309{
2310 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2311 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2312 return false;
2313}
2314
2315static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
2316{
2317 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2318 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
2319 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
2320 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2321 return true;
2322 }
2323 switch (dalvikOpCode) {
2324 case OP_RETURN_VOID:
2325 genReturnCommon(cUnit,mir);
2326 break;
2327 case OP_UNUSED_73:
2328 case OP_UNUSED_79:
2329 case OP_UNUSED_7A:
2330 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2331 return true;
2332 case OP_NOP:
2333 break;
2334 default:
2335 return true;
2336 }
2337 return false;
2338}
2339
2340static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2341{
Bill Buzbee1465db52009-09-23 17:17:35 -07002342 RegLocation rlDest;
2343 RegLocation rlResult;
2344 if (mir->ssaRep->numDefs == 2) {
2345 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2346 } else {
2347 rlDest = getDestLoc(cUnit, mir, 0);
2348 }
Ben Chenge9695e52009-06-16 16:11:47 -07002349
Ben Chengba4fc8b2009-06-01 13:00:29 -07002350 switch (mir->dalvikInsn.opCode) {
2351 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07002352 case OP_CONST_4: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002353 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2354 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2355 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002356 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002357 }
2358 case OP_CONST_WIDE_32: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002359 //TUNING: single routine to load constant pair for support doubles
2360 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2361 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2362 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2363 rlResult.lowReg, 31);
2364 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002365 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002366 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002367 default:
2368 return true;
2369 }
2370 return false;
2371}
2372
2373static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2374{
Bill Buzbee1465db52009-09-23 17:17:35 -07002375 RegLocation rlDest;
2376 RegLocation rlResult;
2377 if (mir->ssaRep->numDefs == 2) {
2378 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2379 } else {
2380 rlDest = getDestLoc(cUnit, mir, 0);
2381 }
2382 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Ben Chenge9695e52009-06-16 16:11:47 -07002383
Ben Chengba4fc8b2009-06-01 13:00:29 -07002384 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07002385 case OP_CONST_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002386 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
2387 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002388 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002389 }
2390 case OP_CONST_WIDE_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002391 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
2392 0, mir->dalvikInsn.vB << 16);
2393 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002394 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002395 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002396 default:
2397 return true;
2398 }
2399 return false;
2400}
2401
2402static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2403{
2404 /* For OP_THROW_VERIFICATION_ERROR */
2405 genInterpSingleStep(cUnit, mir);
2406 return false;
2407}
2408
2409static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2410{
Bill Buzbee1465db52009-09-23 17:17:35 -07002411 RegLocation rlResult;
2412 RegLocation rlDest;
2413 RegLocation rlSrc;
Ben Chenge9695e52009-06-16 16:11:47 -07002414
Ben Chengba4fc8b2009-06-01 13:00:29 -07002415 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002416 case OP_CONST_STRING_JUMBO:
2417 case OP_CONST_STRING: {
2418 void *strPtr = (void*)
2419 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2420 assert(strPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002421 rlDest = getDestLoc(cUnit, mir, 0);
2422 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2423 loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
2424 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002425 break;
2426 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002427 case OP_CONST_CLASS: {
2428 void *classPtr = (void*)
2429 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2430 assert(classPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002431 rlDest = getDestLoc(cUnit, mir, 0);
2432 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2433 loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
2434 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002435 break;
2436 }
2437 case OP_SGET_OBJECT:
2438 case OP_SGET_BOOLEAN:
2439 case OP_SGET_CHAR:
2440 case OP_SGET_BYTE:
2441 case OP_SGET_SHORT:
2442 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002443 int valOffset = offsetof(StaticField, value);
Bill Buzbee1465db52009-09-23 17:17:35 -07002444 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002445 void *fieldPtr = (void*)
2446 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2447 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002448 rlDest = getDestLoc(cUnit, mir, 0);
2449 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2450 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002451#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002452 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002453#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002454 int regMap = rlResult.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002455 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2456
Jeff Hao97319a82009-08-12 16:57:15 -07002457#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002458 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002459 break;
2460 }
2461 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002462 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002463 void *fieldPtr = (void*)
2464 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Bill Buzbee1465db52009-09-23 17:17:35 -07002465 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002466 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002467 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2468 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2469 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002470#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002471 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002472#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002473 int regMap = rlResult.highReg << 16 |
2474 rlResult.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002475 selfVerificationMemOpWrapper(cUnit, regMap,
2476 &selfVerificationLoadDoubleword);
2477
Jeff Hao97319a82009-08-12 16:57:15 -07002478#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002479 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002480 break;
2481 }
2482 case OP_SPUT_OBJECT:
2483 case OP_SPUT_BOOLEAN:
2484 case OP_SPUT_CHAR:
2485 case OP_SPUT_BYTE:
2486 case OP_SPUT_SHORT:
2487 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002488 int valOffset = offsetof(StaticField, value);
Bill Buzbee1465db52009-09-23 17:17:35 -07002489 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002490 void *fieldPtr = (void*)
2491 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002492
Ben Chengba4fc8b2009-06-01 13:00:29 -07002493 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002494 rlSrc = getSrcLoc(cUnit, mir, 0);
2495 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
2496 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002497#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002498 storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002499#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002500 int regMap = rlSrc.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002501 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2502#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002503 break;
2504 }
2505 case OP_SPUT_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002506 int tReg = allocTemp(cUnit);
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002507 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002508 void *fieldPtr = (void*)
2509 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002510
Ben Chengba4fc8b2009-06-01 13:00:29 -07002511 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002512 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2513 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
2514 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002515#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002516 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002517#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002518 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002519 selfVerificationMemOpWrapper(cUnit, regMap,
2520 &selfVerificationStoreDoubleword);
2521#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002522 break;
2523 }
2524 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002525 /*
2526 * Obey the calling convention and don't mess with the register
2527 * usage.
2528 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002529 ClassObject *classPtr = (void*)
2530 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2531 assert(classPtr != NULL);
2532 assert(classPtr->status & CLASS_INITIALIZED);
Ben Cheng79d173c2009-09-29 16:12:51 -07002533 /*
2534 * If it is going to throw, it should not make to the trace to begin
Bill Buzbee1465db52009-09-23 17:17:35 -07002535 * with. However, Alloc might throw, so we need to genExportPC()
Ben Cheng79d173c2009-09-29 16:12:51 -07002536 */
2537 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002538 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002539 genExportPC(cUnit, mir);
2540 loadConstant(cUnit, r2, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002541 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002542 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07002543 opReg(cUnit, kOpBlx, r2);
2544 clobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07002545 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07002546 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2547 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07002548 /*
2549 * OOM exception needs to be thrown here and cannot re-execute
2550 */
2551 loadConstant(cUnit, r0,
2552 (int) (cUnit->method->insns + mir->offset));
2553 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2554 /* noreturn */
2555
Bill Buzbee1465db52009-09-23 17:17:35 -07002556 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07002557 target->defMask = ENCODE_ALL;
2558 branchOver->generic.target = (LIR *) target;
Bill Buzbee1465db52009-09-23 17:17:35 -07002559 rlDest = getDestLoc(cUnit, mir, 0);
2560 rlResult = getReturnLoc(cUnit);
2561 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002562 break;
2563 }
2564 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002565 /*
2566 * Obey the calling convention and don't mess with the register
2567 * usage.
2568 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002569 ClassObject *classPtr =
2570 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002571 flushAllRegs(cUnit); /* Send everything to home location */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002572 loadConstant(cUnit, r1, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07002573 rlSrc = getSrcLoc(cUnit, mir, 0);
2574 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2575 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); /* Null? */
2576 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
2577 /*
2578 * rlSrc.lowReg now contains object->clazz. Note that
2579 * it could have been allocated r0, but we're okay so long
2580 * as we don't do anything desctructive until r0 is loaded
2581 * with clazz.
2582 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002583 /* r0 now contains object->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07002584 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
2585 loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
2586 opRegReg(cUnit, kOpCmp, r0, r1);
2587 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2588 opReg(cUnit, kOpBlx, r2);
2589 clobberCallRegs(cUnit);
2590 /*
2591 * If null, check cast failed - punt to the interpreter. Because
2592 * interpreter will be the one throwing, we don't need to
2593 * genExportPC() here.
2594 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002595 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002596 /* check cast passed - branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07002597 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07002598 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002599 branch1->generic.target = (LIR *)target;
2600 branch2->generic.target = (LIR *)target;
2601 break;
2602 }
2603 default:
2604 return true;
2605 }
2606 return false;
2607}
2608
2609static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2610{
2611 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002612 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002613 switch (dalvikOpCode) {
2614 case OP_MOVE_EXCEPTION: {
2615 int offset = offsetof(InterpState, self);
2616 int exOffset = offsetof(Thread, exception);
Bill Buzbee1465db52009-09-23 17:17:35 -07002617 int selfReg = allocTemp(cUnit);
2618 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2619 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2620 loadWordDisp(cUnit, rGLUE, offset, selfReg);
2621 loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
2622 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002623 break;
2624 }
2625 case OP_MOVE_RESULT:
2626 case OP_MOVE_RESULT_OBJECT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002627 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2628 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
2629 rlSrc.fp = rlDest.fp;
2630 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002631 break;
2632 }
2633 case OP_MOVE_RESULT_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002634 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
2635 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
2636 rlSrc.fp = rlDest.fp;
2637 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002638 break;
2639 }
2640 case OP_RETURN_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002641 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2642 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
2643 rlDest.fp = rlSrc.fp;
2644 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002645 genReturnCommon(cUnit,mir);
2646 break;
2647 }
2648 case OP_RETURN:
2649 case OP_RETURN_OBJECT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002650 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2651 RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
2652 rlDest.fp = rlSrc.fp;
2653 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002654 genReturnCommon(cUnit,mir);
2655 break;
2656 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002657 case OP_MONITOR_EXIT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002658 case OP_MONITOR_ENTER:
Bill Buzbee1465db52009-09-23 17:17:35 -07002659#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
2660 handleMonitorPortable(cUnit, mir);
2661#else
2662 handleMonitor(cUnit, mir);
2663#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002664 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002665 case OP_THROW: {
2666 genInterpSingleStep(cUnit, mir);
2667 break;
2668 }
2669 default:
2670 return true;
2671 }
2672 return false;
2673}
2674
Bill Buzbee1465db52009-09-23 17:17:35 -07002675static bool handleConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002676{
2677 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002678
Ben Chengba4fc8b2009-06-01 13:00:29 -07002679 float __aeabi_i2f( int op1 );
2680 int __aeabi_f2iz( float op1 );
2681 float __aeabi_d2f( double op1 );
2682 double __aeabi_f2d( float op1 );
2683 double __aeabi_i2d( int op1 );
2684 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002685 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002686 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002687 s8 dvmJitf2l( float op1 );
2688 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002689
Bill Buzbeed45ba372009-06-15 17:00:57 -07002690 switch (opCode) {
2691 case OP_INT_TO_FLOAT:
2692 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2693 case OP_FLOAT_TO_INT:
2694 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2695 case OP_DOUBLE_TO_FLOAT:
2696 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2697 case OP_FLOAT_TO_DOUBLE:
2698 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2699 case OP_INT_TO_DOUBLE:
2700 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2701 case OP_DOUBLE_TO_INT:
2702 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2703 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002704 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002705 case OP_LONG_TO_FLOAT:
2706 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2707 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002708 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002709 case OP_LONG_TO_DOUBLE:
2710 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2711 default:
2712 return true;
2713 }
2714 return false;
2715}
2716
2717static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2718{
2719 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002720 RegLocation rlDest;
2721 RegLocation rlSrc;
2722 RegLocation rlResult;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002723
Ben Chengba4fc8b2009-06-01 13:00:29 -07002724 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002725 return handleArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002726 }
2727
Bill Buzbee1465db52009-09-23 17:17:35 -07002728 if (mir->ssaRep->numUses == 2)
2729 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2730 else
2731 rlSrc = getSrcLoc(cUnit, mir, 0);
2732 if (mir->ssaRep->numDefs == 2)
2733 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2734 else
2735 rlDest = getDestLoc(cUnit, mir, 0);
Ben Chenge9695e52009-06-16 16:11:47 -07002736
Ben Chengba4fc8b2009-06-01 13:00:29 -07002737 switch (opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002738 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002739 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002740 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002741 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002742 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002743 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002744 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002745 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002746 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002747 case OP_LONG_TO_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002748 return handleConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002749 case OP_NEG_INT:
2750 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002751 return handleArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002752 case OP_NEG_LONG:
2753 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07002754 return handleArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002755 case OP_NEG_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002756 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002757 case OP_NEG_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002758 return handleArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
2759 case OP_MOVE_WIDE:
2760 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002761 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07002762 case OP_INT_TO_LONG:
2763 rlSrc = updateLoc(cUnit, rlSrc);
2764 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2765 if (rlSrc.location == kLocPhysReg) {
2766 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2767 } else {
2768 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
2769 }
2770 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2771 rlResult.lowReg, 31);
2772 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002773 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07002774 case OP_LONG_TO_INT:
2775 rlSrc = updateLocWide(cUnit, rlSrc);
2776 rlSrc = wideToNarrowLoc(cUnit, rlSrc);
2777 // Intentional fallthrough
Ben Chengba4fc8b2009-06-01 13:00:29 -07002778 case OP_MOVE:
2779 case OP_MOVE_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002780 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002781 break;
2782 case OP_INT_TO_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002783 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2784 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2785 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
2786 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002787 break;
2788 case OP_INT_TO_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002789 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2790 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2791 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
2792 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002793 break;
2794 case OP_INT_TO_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002795 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2796 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2797 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
2798 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002799 break;
2800 case OP_ARRAY_LENGTH: {
2801 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07002802 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2803 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
2804 mir->offset, NULL);
2805 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2806 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
2807 rlResult.lowReg);
2808 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002809 break;
2810 }
2811 default:
2812 return true;
2813 }
2814 return false;
2815}
2816
2817static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2818{
2819 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002820 RegLocation rlDest;
2821 RegLocation rlResult;
2822 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002823 if (dalvikOpCode == OP_CONST_WIDE_16) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002824 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2825 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2826 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
2827 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
2828 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002829 } else if (dalvikOpCode == OP_CONST_16) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002830 rlDest = getDestLoc(cUnit, mir, 0);
2831 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2832 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
2833 storeValue(cUnit, rlDest, rlResult);
2834 } else
Ben Chengba4fc8b2009-06-01 13:00:29 -07002835 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002836 return false;
2837}
2838
2839/* Compare agaist zero */
2840static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002841 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002842{
2843 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002844 ArmConditionCode cond;
Bill Buzbee1465db52009-09-23 17:17:35 -07002845 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2846 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2847 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002848
Bill Buzbee270c1d62009-08-13 16:58:07 -07002849//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002850 switch (dalvikOpCode) {
2851 case OP_IF_EQZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002852 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002853 break;
2854 case OP_IF_NEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002855 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002856 break;
2857 case OP_IF_LTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002858 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002859 break;
2860 case OP_IF_GEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002861 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002862 break;
2863 case OP_IF_GTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002864 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002865 break;
2866 case OP_IF_LEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002867 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002868 break;
2869 default:
2870 cond = 0;
2871 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2872 dvmAbort();
2873 }
2874 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2875 /* This mostly likely will be optimized away in a later phase */
2876 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2877 return false;
2878}
2879
2880static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2881{
2882 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002883 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2884 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2885 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002886 int lit = mir->dalvikInsn.vC;
Ben Cheng4f489172009-09-27 17:08:35 -07002887 OpKind op = 0; /* Make gcc happy */
Bill Buzbee1465db52009-09-23 17:17:35 -07002888 int shiftOp = false;
2889 bool isDiv = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002890
Ben Chengba4fc8b2009-06-01 13:00:29 -07002891 int __aeabi_idivmod(int op1, int op2);
2892 int __aeabi_idiv(int op1, int op2);
2893
2894 switch (dalvikOpCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002895 case OP_RSUB_INT_LIT8:
2896 case OP_RSUB_INT: {
2897 int tReg;
2898 //TUNING: add support for use of Arm rsub op
2899 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2900 tReg = allocTemp(cUnit);
2901 loadConstant(cUnit, tReg, lit);
2902 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2903 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
2904 tReg, rlSrc.lowReg);
2905 storeValue(cUnit, rlDest, rlResult);
2906 return false;
2907 break;
2908 }
2909
Ben Chengba4fc8b2009-06-01 13:00:29 -07002910 case OP_ADD_INT_LIT8:
2911 case OP_ADD_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002912 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002913 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002914 case OP_MUL_INT_LIT8:
2915 case OP_MUL_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002916 op = kOpMul;
2917 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002918 case OP_AND_INT_LIT8:
2919 case OP_AND_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002920 op = kOpAnd;
2921 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002922 case OP_OR_INT_LIT8:
2923 case OP_OR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002924 op = kOpOr;
2925 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002926 case OP_XOR_INT_LIT8:
2927 case OP_XOR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002928 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002929 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002930 case OP_SHL_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002931 shiftOp = true;
2932 op = kOpLsl;
2933 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002934 case OP_SHR_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002935 shiftOp = true;
2936 op = kOpAsr;
2937 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002938 case OP_USHR_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002939 shiftOp = true;
2940 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002941 break;
2942
2943 case OP_DIV_INT_LIT8:
2944 case OP_DIV_INT_LIT16:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002945 case OP_REM_INT_LIT8:
2946 case OP_REM_INT_LIT16:
2947 if (lit == 0) {
2948 /* Let the interpreter deal with div by 0 */
2949 genInterpSingleStep(cUnit, mir);
2950 return false;
2951 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002952 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002953 loadValueDirectFixed(cUnit, rlSrc, r0);
2954 clobberReg(cUnit, r0);
2955 if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2956 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2957 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2958 isDiv = true;
2959 } else {
2960 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2961 isDiv = false;
2962 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002963 loadConstant(cUnit, r1, lit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002964 opReg(cUnit, kOpBlx, r2);
2965 clobberCallRegs(cUnit);
2966 if (isDiv)
2967 rlResult = getReturnLoc(cUnit);
2968 else
2969 rlResult = getReturnLocAlt(cUnit);
2970 storeValue(cUnit, rlDest, rlResult);
2971 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002972 break;
2973 default:
2974 return true;
2975 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002976 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2977 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2978 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2979 if (shiftOp && (lit == 0)) {
2980 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2981 } else {
2982 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2983 }
2984 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002985 return false;
2986}
2987
2988static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2989{
2990 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2991 int fieldOffset;
2992
2993 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2994 InstField *pInstField = (InstField *)
2995 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002996
2997 assert(pInstField != NULL);
2998 fieldOffset = pInstField->byteOffset;
2999 } else {
Ben Chenga0e7b602009-10-13 23:09:01 -07003000 /* Deliberately break the code while make the compiler happy */
3001 fieldOffset = -1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003002 }
3003 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07003004 case OP_NEW_ARRAY: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003005 // Generates a call - use explicit registers
3006 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3007 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
3008 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003009 void *classPtr = (void*)
3010 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
3011 assert(classPtr != NULL);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003012 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003013 genExportPC(cUnit, mir);
3014 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003015 loadConstant(cUnit, r0, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07003016 loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
Ben Cheng4f489172009-09-27 17:08:35 -07003017 /*
3018 * "len < 0": bail to the interpreter to re-execute the
3019 * instruction
3020 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003021 ArmLIR *pcrLabel =
Bill Buzbee1465db52009-09-23 17:17:35 -07003022 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003023 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07003024 opReg(cUnit, kOpBlx, r3);
3025 clobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07003026 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07003027 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3028 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07003029 /*
3030 * OOM exception needs to be thrown here and cannot re-execute
3031 */
3032 loadConstant(cUnit, r0,
3033 (int) (cUnit->method->insns + mir->offset));
3034 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3035 /* noreturn */
3036
Bill Buzbee1465db52009-09-23 17:17:35 -07003037 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07003038 target->defMask = ENCODE_ALL;
3039 branchOver->generic.target = (LIR *) target;
Bill Buzbee1465db52009-09-23 17:17:35 -07003040 rlResult = getReturnLoc(cUnit);
3041 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003042 break;
3043 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003044 case OP_INSTANCE_OF: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003045 // May generate a call - use explicit registers
3046 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3047 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
3048 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003049 ClassObject *classPtr =
3050 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
3051 assert(classPtr != NULL);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003052 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003053 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003054 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07003055//TUNING: compare to 0 primative to allow use of CB[N]Z
Bill Buzbee1465db52009-09-23 17:17:35 -07003056 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07003057 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee1465db52009-09-23 17:17:35 -07003058 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003059 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003060 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07003061 /* r1 now contains object->clazz */
3062 loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07003063 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee1465db52009-09-23 17:17:35 -07003064 opRegReg(cUnit, kOpCmp, r1, r2);
3065 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
3066 genRegCopy(cUnit, r0, r1);
3067 genRegCopy(cUnit, r1, r2);
3068 opReg(cUnit, kOpBlx, r3);
3069 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003070 /* branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07003071 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07003072 target->defMask = ENCODE_ALL;
Bill Buzbee1465db52009-09-23 17:17:35 -07003073 rlResult = getReturnLoc(cUnit);
3074 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003075 branch1->generic.target = (LIR *)target;
3076 branch2->generic.target = (LIR *)target;
3077 break;
3078 }
3079 case OP_IGET_WIDE:
3080 genIGetWide(cUnit, mir, fieldOffset);
3081 break;
3082 case OP_IGET:
3083 case OP_IGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003084 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003085 break;
3086 case OP_IGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003087 genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003088 break;
3089 case OP_IGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003090 genIGet(cUnit, mir, kSignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003091 break;
3092 case OP_IGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003093 genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003094 break;
3095 case OP_IGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003096 genIGet(cUnit, mir, kSignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003097 break;
3098 case OP_IPUT_WIDE:
3099 genIPutWide(cUnit, mir, fieldOffset);
3100 break;
3101 case OP_IPUT:
3102 case OP_IPUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003103 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003104 break;
3105 case OP_IPUT_SHORT:
3106 case OP_IPUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003107 genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003108 break;
3109 case OP_IPUT_BYTE:
3110 case OP_IPUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003111 genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003112 break;
3113 default:
3114 return true;
3115 }
3116 return false;
3117}
3118
3119static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
3120{
3121 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3122 int fieldOffset = mir->dalvikInsn.vC;
3123 switch (dalvikOpCode) {
3124 case OP_IGET_QUICK:
3125 case OP_IGET_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07003126 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003127 break;
3128 case OP_IPUT_QUICK:
3129 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07003130 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003131 break;
3132 case OP_IGET_WIDE_QUICK:
3133 genIGetWide(cUnit, mir, fieldOffset);
3134 break;
3135 case OP_IPUT_WIDE_QUICK:
3136 genIPutWide(cUnit, mir, fieldOffset);
3137 break;
3138 default:
3139 return true;
3140 }
3141 return false;
3142
3143}
3144
3145/* Compare agaist zero */
3146static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003147 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003148{
3149 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003150 ArmConditionCode cond;
Bill Buzbee1465db52009-09-23 17:17:35 -07003151 RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
3152 RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003153
Bill Buzbee1465db52009-09-23 17:17:35 -07003154 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
3155 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
3156 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003157
3158 switch (dalvikOpCode) {
3159 case OP_IF_EQ:
Bill Buzbee1465db52009-09-23 17:17:35 -07003160 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003161 break;
3162 case OP_IF_NE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003163 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003164 break;
3165 case OP_IF_LT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003166 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003167 break;
3168 case OP_IF_GE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003169 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003170 break;
3171 case OP_IF_GT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003172 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003173 break;
3174 case OP_IF_LE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003175 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003176 break;
3177 default:
3178 cond = 0;
3179 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
3180 dvmAbort();
3181 }
3182 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
3183 /* This mostly likely will be optimized away in a later phase */
3184 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
3185 return false;
3186}
3187
3188static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
3189{
3190 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003191
3192 switch (opCode) {
3193 case OP_MOVE_16:
3194 case OP_MOVE_OBJECT_16:
3195 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07003196 case OP_MOVE_OBJECT_FROM16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003197 storeValue(cUnit, getDestLoc(cUnit, mir, 0),
3198 getSrcLoc(cUnit, mir, 0));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003199 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003200 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003201 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07003202 case OP_MOVE_WIDE_FROM16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003203 storeValueWide(cUnit, getDestLocWide(cUnit, mir, 0, 1),
3204 getSrcLocWide(cUnit, mir, 0, 1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003205 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003206 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003207 default:
3208 return true;
3209 }
3210 return false;
3211}
3212
3213static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
3214{
3215 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07003216 RegLocation rlSrc1;
3217 RegLocation rlSrc2;
3218 RegLocation rlDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003219
3220 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003221 return handleArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07003222 }
3223
Bill Buzbee1465db52009-09-23 17:17:35 -07003224 /* APUTs have 3 sources and no targets */
3225 if (mir->ssaRep->numDefs == 0) {
3226 if (mir->ssaRep->numUses == 3) {
3227 rlDest = getSrcLoc(cUnit, mir, 0);
3228 rlSrc1 = getSrcLoc(cUnit, mir, 1);
3229 rlSrc2 = getSrcLoc(cUnit, mir, 2);
3230 } else {
3231 assert(mir->ssaRep->numUses == 4);
3232 rlDest = getSrcLocWide(cUnit, mir, 0, 1);
3233 rlSrc1 = getSrcLoc(cUnit, mir, 2);
3234 rlSrc2 = getSrcLoc(cUnit, mir, 3);
3235 }
3236 } else {
3237 /* Two sources and 1 dest. Deduce the operand sizes */
3238 if (mir->ssaRep->numUses == 4) {
3239 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
3240 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
3241 } else {
3242 assert(mir->ssaRep->numUses == 2);
3243 rlSrc1 = getSrcLoc(cUnit, mir, 0);
3244 rlSrc2 = getSrcLoc(cUnit, mir, 1);
3245 }
3246 if (mir->ssaRep->numDefs == 2) {
3247 rlDest = getDestLocWide(cUnit, mir, 0, 1);
3248 } else {
3249 assert(mir->ssaRep->numDefs == 1);
3250 rlDest = getDestLoc(cUnit, mir, 0);
3251 }
3252 }
3253
3254
Ben Chengba4fc8b2009-06-01 13:00:29 -07003255 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07003256 case OP_CMPL_FLOAT:
3257 case OP_CMPG_FLOAT:
3258 case OP_CMPL_DOUBLE:
3259 case OP_CMPG_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003260 return handleCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003261 case OP_CMP_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07003262 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003263 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003264 case OP_AGET_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003265 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003266 break;
3267 case OP_AGET:
3268 case OP_AGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003269 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003270 break;
3271 case OP_AGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003272 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003273 break;
3274 case OP_AGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003275 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003276 break;
3277 case OP_AGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003278 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003279 break;
3280 case OP_AGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003281 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003282 break;
3283 case OP_APUT_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003284 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003285 break;
3286 case OP_APUT:
3287 case OP_APUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003288 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003289 break;
3290 case OP_APUT_SHORT:
3291 case OP_APUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003292 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003293 break;
3294 case OP_APUT_BYTE:
3295 case OP_APUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003296 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003297 break;
3298 default:
3299 return true;
3300 }
3301 return false;
3302}
3303
Ben Cheng6c10a972009-10-29 14:39:18 -07003304/*
3305 * Find the matching case.
3306 *
3307 * return values:
3308 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
3309 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
3310 * r1 (high 32-bit): the branch offset of the matching case (only for indexes
3311 * above MAX_CHAINED_SWITCH_CASES).
3312 *
3313 * Instructions around the call are:
3314 *
3315 * mov r2, pc
3316 * blx &findPackedSwitchIndex
3317 * mov pc, r0
3318 * .align4
3319 * chaining cell for case 0 [8 bytes]
3320 * chaining cell for case 1 [8 bytes]
3321 * :
3322 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
3323 * chaining cell for case default [8 bytes]
3324 * noChain exit
3325 */
3326s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
3327{
3328 int size;
3329 int firstKey;
3330 const int *entries;
3331 int index;
3332 int jumpIndex;
3333 int caseDPCOffset = 0;
3334 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
3335 int chainingPC = (pc + 4) & ~3;
3336
3337 /*
3338 * Packed switch data format:
3339 * ushort ident = 0x0100 magic value
3340 * ushort size number of entries in the table
3341 * int first_key first (and lowest) switch case value
3342 * int targets[size] branch targets, relative to switch opcode
3343 *
3344 * Total size is (4+size*2) 16-bit code units.
3345 */
3346 size = switchData[1];
3347 assert(size > 0);
3348
3349 firstKey = switchData[2];
3350 firstKey |= switchData[3] << 16;
3351
3352
3353 /* The entries are guaranteed to be aligned on a 32-bit boundary;
3354 * we can treat them as a native int array.
3355 */
3356 entries = (const int*) &switchData[4];
3357 assert(((u4)entries & 0x3) == 0);
3358
3359 index = testVal - firstKey;
3360
3361 /* Jump to the default cell */
3362 if (index < 0 || index >= size) {
3363 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
3364 /* Jump to the non-chaining exit point */
3365 } else if (index >= MAX_CHAINED_SWITCH_CASES) {
3366 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
3367 caseDPCOffset = entries[index];
3368 /* Jump to the inline chaining cell */
3369 } else {
3370 jumpIndex = index;
3371 }
3372
3373 chainingPC += jumpIndex * 8;
3374 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
3375}
3376
3377/* See comments for findPackedSwitchIndex */
3378s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
3379{
3380 int size;
3381 const int *keys;
3382 const int *entries;
3383 int chainingPC = (pc + 4) & ~3;
3384 int i;
3385
3386 /*
3387 * Sparse switch data format:
3388 * ushort ident = 0x0200 magic value
3389 * ushort size number of entries in the table; > 0
3390 * int keys[size] keys, sorted low-to-high; 32-bit aligned
3391 * int targets[size] branch targets, relative to switch opcode
3392 *
3393 * Total size is (2+size*4) 16-bit code units.
3394 */
3395
3396 size = switchData[1];
3397 assert(size > 0);
3398
3399 /* The keys are guaranteed to be aligned on a 32-bit boundary;
3400 * we can treat them as a native int array.
3401 */
3402 keys = (const int*) &switchData[2];
3403 assert(((u4)keys & 0x3) == 0);
3404
3405 /* The entries are guaranteed to be aligned on a 32-bit boundary;
3406 * we can treat them as a native int array.
3407 */
3408 entries = keys + size;
3409 assert(((u4)entries & 0x3) == 0);
3410
3411 /*
3412 * Run through the list of keys, which are guaranteed to
3413 * be sorted low-to-high.
3414 *
3415 * Most tables have 3-4 entries. Few have more than 10. A binary
3416 * search here is probably not useful.
3417 */
3418 for (i = 0; i < size; i++) {
3419 int k = keys[i];
3420 if (k == testVal) {
3421 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
3422 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
3423 i : MAX_CHAINED_SWITCH_CASES + 1;
3424 chainingPC += jumpIndex * 8;
3425 return (((s8) entries[i]) << 32) | (u8) chainingPC;
3426 } else if (k > testVal) {
3427 break;
3428 }
3429 }
3430 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
3431}
3432
Ben Chengba4fc8b2009-06-01 13:00:29 -07003433static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
3434{
3435 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3436 switch (dalvikOpCode) {
3437 case OP_FILL_ARRAY_DATA: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003438 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3439 // Making a call - use explicit registers
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003440 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003441 genExportPC(cUnit, mir);
3442 loadValueDirectFixed(cUnit, rlSrc, r0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003443 loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData);
Ben Cheng6c10a972009-10-29 14:39:18 -07003444 loadConstant(cUnit, r1,
3445 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
Bill Buzbee1465db52009-09-23 17:17:35 -07003446 opReg(cUnit, kOpBlx, r2);
3447 clobberCallRegs(cUnit);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003448 /* generate a branch over if successful */
3449 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3450 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3451 loadConstant(cUnit, r0,
3452 (int) (cUnit->method->insns + mir->offset));
3453 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3454 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3455 target->defMask = ENCODE_ALL;
3456 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003457 break;
3458 }
3459 /*
Ben Cheng6c10a972009-10-29 14:39:18 -07003460 * Compute the goto target of up to
3461 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
3462 * See the comment before findPackedSwitchIndex for the code layout.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003463 */
3464 case OP_PACKED_SWITCH:
3465 case OP_SPARSE_SWITCH: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003466 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003467 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003468 loadValueDirectFixed(cUnit, rlSrc, r1);
3469 lockAllTemps(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07003470 const u2 *switchData =
3471 cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
3472 u2 size = switchData[1];
3473
Ben Chengba4fc8b2009-06-01 13:00:29 -07003474 if (dalvikOpCode == OP_PACKED_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -07003475 loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003476 } else {
Ben Cheng6c10a972009-10-29 14:39:18 -07003477 loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003478 }
Ben Cheng6c10a972009-10-29 14:39:18 -07003479 /* r0 <- Addr of the switch data */
3480 loadConstant(cUnit, r0,
3481 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
3482 /* r2 <- pc of the instruction following the blx */
3483 opRegReg(cUnit, kOpMov, r2, rpc);
Bill Buzbee1465db52009-09-23 17:17:35 -07003484 opReg(cUnit, kOpBlx, r4PC);
3485 clobberCallRegs(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07003486 /* pc <- computed goto target */
3487 opRegReg(cUnit, kOpMov, rpc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003488 break;
3489 }
3490 default:
3491 return true;
3492 }
3493 return false;
3494}
3495
3496static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003497 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003498{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003499 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003500 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003501
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003502 if (bb->fallThrough != NULL)
3503 retChainingCell = &labelList[bb->fallThrough->id];
3504
Ben Chengba4fc8b2009-06-01 13:00:29 -07003505 DecodedInstruction *dInsn = &mir->dalvikInsn;
3506 switch (mir->dalvikInsn.opCode) {
3507 /*
3508 * calleeMethod = this->clazz->vtable[
3509 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3510 * ]
3511 */
3512 case OP_INVOKE_VIRTUAL:
3513 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003514 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003515 int methodIndex =
3516 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3517 methodIndex;
3518
3519 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3520 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3521 else
3522 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3523
Ben Cheng38329f52009-07-07 14:19:20 -07003524 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3525 retChainingCell,
3526 predChainingCell,
3527 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003528 break;
3529 }
3530 /*
3531 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3532 * ->pResMethods[BBBB]->methodIndex]
3533 */
3534 /* TODO - not excersized in RunPerf.jar */
3535 case OP_INVOKE_SUPER:
3536 case OP_INVOKE_SUPER_RANGE: {
3537 int mIndex = cUnit->method->clazz->pDvmDex->
3538 pResMethods[dInsn->vB]->methodIndex;
3539 const Method *calleeMethod =
3540 cUnit->method->clazz->super->vtable[mIndex];
3541
3542 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3543 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3544 else
3545 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3546
3547 /* r0 = calleeMethod */
3548 loadConstant(cUnit, r0, (int) calleeMethod);
3549
Ben Cheng38329f52009-07-07 14:19:20 -07003550 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3551 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003552 break;
3553 }
3554 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3555 case OP_INVOKE_DIRECT:
3556 case OP_INVOKE_DIRECT_RANGE: {
3557 const Method *calleeMethod =
3558 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3559
3560 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3561 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3562 else
3563 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3564
3565 /* r0 = calleeMethod */
3566 loadConstant(cUnit, r0, (int) calleeMethod);
3567
Ben Cheng38329f52009-07-07 14:19:20 -07003568 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3569 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003570 break;
3571 }
3572 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3573 case OP_INVOKE_STATIC:
3574 case OP_INVOKE_STATIC_RANGE: {
3575 const Method *calleeMethod =
3576 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3577
3578 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3579 genProcessArgsNoRange(cUnit, mir, dInsn,
3580 NULL /* no null check */);
3581 else
3582 genProcessArgsRange(cUnit, mir, dInsn,
3583 NULL /* no null check */);
3584
3585 /* r0 = calleeMethod */
3586 loadConstant(cUnit, r0, (int) calleeMethod);
3587
Ben Cheng38329f52009-07-07 14:19:20 -07003588 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3589 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003590 break;
3591 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003592 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -07003593 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3594 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003595 *
3596 * Given "invoke-interface {v0}", the following is the generated code:
3597 *
3598 * 0x426a9abe : ldr r0, [r5, #0] --+
3599 * 0x426a9ac0 : mov r7, r5 |
3600 * 0x426a9ac2 : sub r7, #24 |
3601 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3602 * 0x426a9ac6 : beq 0x426a9afe |
3603 * 0x426a9ac8 : stmia r7, <r0> --+
3604 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3605 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3606 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3607 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3608 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3609 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3610 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
Ben Chenga8e64a72009-10-20 13:01:36 -07003611 * 0x426a9ad8 : mov r8, r1 --+
3612 * 0x426a9ada : mov r9, r2 |
3613 * 0x426a9adc : mov r10, r3 |
Ben Cheng38329f52009-07-07 14:19:20 -07003614 * 0x426a9ade : mov r0, r3 |
3615 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3616 * 0x426a9ae2 : ldr r2, [pc, #76] |
3617 * 0x426a9ae4 : ldr r3, [pc, #68] |
3618 * 0x426a9ae6 : ldr r7, [pc, #64] |
3619 * 0x426a9ae8 : blx r7 --+
Ben Chenga8e64a72009-10-20 13:01:36 -07003620 * 0x426a9aea : mov r1, r8 --> r1 <- rechain count
Ben Cheng38329f52009-07-07 14:19:20 -07003621 * 0x426a9aec : cmp r1, #0 --> compare against 0
3622 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3623 * 0x426a9af0 : ldr r7, [r6, #96] --+
Ben Chenga8e64a72009-10-20 13:01:36 -07003624 * 0x426a9af2 : mov r2, r9 | dvmJitToPatchPredictedChain
3625 * 0x426a9af4 : mov r3, r10 |
Ben Cheng38329f52009-07-07 14:19:20 -07003626 * 0x426a9af6 : blx r7 --+
3627 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3628 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3629 * 0x426a9afc : blx_2 see above --+
3630 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3631 * 0x426a9afe (0042): ldr r0, [pc, #52]
3632 * Exception_Handling:
3633 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3634 * 0x426a9b02 (0046): blx r1
3635 * 0x426a9b04 (0048): .align4
3636 * -------- chaining cell (hot): 0x0021
3637 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3638 * 0x426a9b06 (004a): blx r0
3639 * 0x426a9b08 (004c): data 0x7872(30834)
3640 * 0x426a9b0a (004e): data 0x428b(17035)
3641 * 0x426a9b0c (0050): .align4
3642 * -------- chaining cell (predicted)
3643 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3644 * 0x426a9b0e (0052): data 0x0000(0)
3645 * 0x426a9b10 (0054): data 0x0000(0) --> class
3646 * 0x426a9b12 (0056): data 0x0000(0)
3647 * 0x426a9b14 (0058): data 0x0000(0) --> method
3648 * 0x426a9b16 (005a): data 0x0000(0)
3649 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3650 * 0x426a9b1a (005e): data 0x0000(0)
3651 * 0x426a9b28 (006c): .word (0xad0392a5)
3652 * 0x426a9b2c (0070): .word (0x6e750)
3653 * 0x426a9b30 (0074): .word (0x4109a618)
3654 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003655 */
3656 case OP_INVOKE_INTERFACE:
3657 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003658 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003659 int methodIndex = dInsn->vB;
3660
Bill Buzbee1465db52009-09-23 17:17:35 -07003661 /* Ensure that nothing is both live and dirty */
3662 flushAllRegs(cUnit);
3663
Ben Chengba4fc8b2009-06-01 13:00:29 -07003664 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3665 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3666 else
3667 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3668
Ben Cheng38329f52009-07-07 14:19:20 -07003669 /* "this" is already left in r0 by genProcessArgs* */
3670
3671 /* r4PC = dalvikCallsite */
3672 loadConstant(cUnit, r4PC,
3673 (int) (cUnit->method->insns + mir->offset));
3674
3675 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003676 ArmLIR *addrRetChain =
Bill Buzbee1465db52009-09-23 17:17:35 -07003677 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003678 addrRetChain->generic.target = (LIR *) retChainingCell;
3679
3680 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003681 ArmLIR *predictedChainingCell =
Bill Buzbee1465db52009-09-23 17:17:35 -07003682 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003683 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3684
3685 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3686
3687 /* return through lr - jump to the chaining cell */
3688 genUnconditionalBranch(cUnit, predChainingCell);
3689
3690 /*
3691 * null-check on "this" may have been eliminated, but we still need
3692 * a PC-reconstruction label for stack overflow bailout.
3693 */
3694 if (pcrLabel == NULL) {
3695 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003696 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003697 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003698 pcrLabel->operands[0] = dPC;
3699 pcrLabel->operands[1] = mir->offset;
3700 /* Insert the place holder to the growable list */
3701 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3702 }
3703
3704 /* return through lr+2 - punt to the interpreter */
3705 genUnconditionalBranch(cUnit, pcrLabel);
3706
3707 /*
3708 * return through lr+4 - fully resolve the callee method.
3709 * r1 <- count
3710 * r2 <- &predictedChainCell
3711 * r3 <- this->class
3712 * r4 <- dPC
3713 * r7 <- this->class->vtable
3714 */
3715
3716 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee1465db52009-09-23 17:17:35 -07003717 genRegCopy(cUnit, r8, r1);
3718 genRegCopy(cUnit, r9, r2);
3719 genRegCopy(cUnit, r10, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003720
Ben Chengba4fc8b2009-06-01 13:00:29 -07003721 /* r0 now contains this->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07003722 genRegCopy(cUnit, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003723
3724 /* r1 = BBBB */
3725 loadConstant(cUnit, r1, dInsn->vB);
3726
3727 /* r2 = method (caller) */
3728 loadConstant(cUnit, r2, (int) cUnit->method);
3729
3730 /* r3 = pDvmDex */
3731 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3732
3733 loadConstant(cUnit, r7,
3734 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee1465db52009-09-23 17:17:35 -07003735 opReg(cUnit, kOpBlx, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003736
3737 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3738
Bill Buzbee1465db52009-09-23 17:17:35 -07003739 genRegCopy(cUnit, r1, r8);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003740
Ben Cheng38329f52009-07-07 14:19:20 -07003741 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07003742 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003743
Bill Buzbee1465db52009-09-23 17:17:35 -07003744 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07003745
Bill Buzbee270c1d62009-08-13 16:58:07 -07003746 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3747 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003748
Bill Buzbee1465db52009-09-23 17:17:35 -07003749 genRegCopy(cUnit, r2, r9);
3750 genRegCopy(cUnit, r3, r10);
Ben Cheng38329f52009-07-07 14:19:20 -07003751
3752 /*
3753 * r0 = calleeMethod
3754 * r2 = &predictedChainingCell
3755 * r3 = class
3756 *
3757 * &returnChainingCell has been loaded into r1 but is not needed
3758 * when patching the chaining cell and will be clobbered upon
3759 * returning so it will be reconstructed again.
3760 */
Bill Buzbee1465db52009-09-23 17:17:35 -07003761 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003762
3763 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07003764 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003765 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003766
3767 bypassRechaining->generic.target = (LIR *) addrRetChain;
3768
Ben Chengba4fc8b2009-06-01 13:00:29 -07003769 /*
3770 * r0 = this, r1 = calleeMethod,
3771 * r1 = &ChainingCell,
3772 * r4PC = callsiteDPC,
3773 */
3774 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3775#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003776 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003777#endif
3778 /* Handle exceptions using the interpreter */
3779 genTrap(cUnit, mir->offset, pcrLabel);
3780 break;
3781 }
3782 /* NOP */
3783 case OP_INVOKE_DIRECT_EMPTY: {
3784 return false;
3785 }
3786 case OP_FILLED_NEW_ARRAY:
3787 case OP_FILLED_NEW_ARRAY_RANGE: {
3788 /* Just let the interpreter deal with these */
3789 genInterpSingleStep(cUnit, mir);
3790 break;
3791 }
3792 default:
3793 return true;
3794 }
3795 return false;
3796}
3797
3798static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003799 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003800{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003801 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3802 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3803 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003804
3805 DecodedInstruction *dInsn = &mir->dalvikInsn;
3806 switch (mir->dalvikInsn.opCode) {
3807 /* calleeMethod = this->clazz->vtable[BBBB] */
3808 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3809 case OP_INVOKE_VIRTUAL_QUICK: {
3810 int methodIndex = dInsn->vB;
3811 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3812 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3813 else
3814 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3815
Ben Cheng38329f52009-07-07 14:19:20 -07003816 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3817 retChainingCell,
3818 predChainingCell,
3819 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003820 break;
3821 }
3822 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3823 case OP_INVOKE_SUPER_QUICK:
3824 case OP_INVOKE_SUPER_QUICK_RANGE: {
3825 const Method *calleeMethod =
3826 cUnit->method->clazz->super->vtable[dInsn->vB];
3827
3828 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3829 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3830 else
3831 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3832
3833 /* r0 = calleeMethod */
3834 loadConstant(cUnit, r0, (int) calleeMethod);
3835
Ben Cheng38329f52009-07-07 14:19:20 -07003836 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3837 calleeMethod);
3838 /* Handle exceptions using the interpreter */
3839 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003840 break;
3841 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003842 default:
3843 return true;
3844 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003845 return false;
3846}
3847
3848/*
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003849 * This operation is complex enough that we'll do it partly inline
3850 * and partly with a handler. NOTE: the handler uses hardcoded
3851 * values for string object offsets and must be revisitied if the
3852 * layout changes.
3853 */
3854static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
3855{
3856#if defined(USE_GLOBAL_STRING_DEFS)
3857 return false;
3858#else
3859 ArmLIR *rollback;
3860 RegLocation rlThis = getSrcLoc(cUnit, mir, 0);
3861 RegLocation rlComp = getSrcLoc(cUnit, mir, 1);
3862
3863 loadValueDirectFixed(cUnit, rlThis, r0);
3864 loadValueDirectFixed(cUnit, rlComp, r1);
3865 /* Test objects for NULL */
3866 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3867 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
3868 /*
3869 * TUNING: we could check for object pointer equality before invoking
3870 * handler. Unclear whether the gain would be worth the added code size
3871 * expansion.
3872 */
3873 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
3874 storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit));
3875 return true;
3876#endif
3877}
3878
3879static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
3880{
3881#if defined(USE_GLOBAL_STRING_DEFS)
3882 return false;
3883#else
3884 RegLocation rlThis = getSrcLoc(cUnit, mir, 0);
3885 RegLocation rlChar = getSrcLoc(cUnit, mir, 1);
3886
3887 loadValueDirectFixed(cUnit, rlThis, r0);
3888 loadValueDirectFixed(cUnit, rlChar, r1);
3889 if (!singleI) {
3890 RegLocation rlStart = getSrcLoc(cUnit, mir, 2);
3891 loadValueDirectFixed(cUnit, rlStart, r2);
3892 } else {
3893 loadConstant(cUnit, r2, 0);
3894 }
3895 /* Test objects for NULL */
3896 genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3897 genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
3898 storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit));
3899 return true;
3900#endif
3901}
3902
3903
3904/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07003905 * NOTE: We assume here that the special native inline routines
3906 * are side-effect free. By making this assumption, we can safely
3907 * re-execute the routine from the interpreter if it decides it
3908 * wants to throw an exception. We still need to EXPORT_PC(), though.
3909 */
3910static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3911{
3912 DecodedInstruction *dInsn = &mir->dalvikInsn;
3913 switch( mir->dalvikInsn.opCode) {
3914 case OP_EXECUTE_INLINE: {
3915 unsigned int i;
3916 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003917 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003918 int operation = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07003919 int tReg1;
3920 int tReg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003921 switch (operation) {
3922 case INLINE_EMPTYINLINEMETHOD:
3923 return false; /* Nop */
3924 case INLINE_STRING_LENGTH:
3925 return genInlinedStringLength(cUnit, mir);
3926 case INLINE_MATH_ABS_INT:
3927 return genInlinedAbsInt(cUnit, mir);
3928 case INLINE_MATH_ABS_LONG:
3929 return genInlinedAbsLong(cUnit, mir);
3930 case INLINE_MATH_MIN_INT:
3931 return genInlinedMinMaxInt(cUnit, mir, true);
3932 case INLINE_MATH_MAX_INT:
3933 return genInlinedMinMaxInt(cUnit, mir, false);
3934 case INLINE_STRING_CHARAT:
3935 return genInlinedStringCharAt(cUnit, mir);
3936 case INLINE_MATH_SQRT:
3937 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003938 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003939 else
3940 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003941 case INLINE_MATH_ABS_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003942 if (genInlinedAbsFloat(cUnit, mir))
3943 return false;
3944 else
3945 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003946 case INLINE_MATH_ABS_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003947 if (genInlinedAbsDouble(cUnit, mir))
3948 return false;
3949 else
3950 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003951 case INLINE_STRING_COMPARETO:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003952 if (genInlinedCompareTo(cUnit, mir))
3953 return false;
3954 else
3955 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003956 case INLINE_STRING_INDEXOF_I:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003957 if (genInlinedIndexOf(cUnit, mir, true /* I */))
3958 return false;
3959 else
3960 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003961 case INLINE_STRING_INDEXOF_II:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003962 if (genInlinedIndexOf(cUnit, mir, false /* I */))
3963 return false;
3964 else
3965 break;
3966 case INLINE_STRING_EQUALS:
3967 case INLINE_MATH_COS:
3968 case INLINE_MATH_SIN:
3969 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003970 default:
3971 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003972 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003973 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003974 clobberCallRegs(cUnit);
3975 clobberReg(cUnit, r4PC);
3976 clobberReg(cUnit, r7);
3977 opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3978 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003979 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
Bill Buzbee1465db52009-09-23 17:17:35 -07003980 genExportPC(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003981 for (i=0; i < dInsn->vA; i++) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003982 loadValueDirect(cUnit, getSrcLoc(cUnit, mir, i), i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003983 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003984 opReg(cUnit, kOpBlx, r4PC);
3985 opRegImm(cUnit, kOpAdd, r13, 8);
Ben Chenge9695e52009-06-16 16:11:47 -07003986 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003987 break;
3988 }
3989 default:
3990 return true;
3991 }
3992 return false;
3993}
3994
3995static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3996{
Bill Buzbee1465db52009-09-23 17:17:35 -07003997 //TUNING: We're using core regs here - not optimal when target is a double
3998 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
3999 RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
4000 loadConstantValue(cUnit, rlResult.lowReg,
4001 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
4002 loadConstantValue(cUnit, rlResult.highReg,
4003 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
4004 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004005 return false;
4006}
4007
Ben Chengba4fc8b2009-06-01 13:00:29 -07004008/*
4009 * The following are special processing routines that handle transfer of
4010 * controls between compiled code and the interpreter. Certain VM states like
4011 * Dalvik PC and special-purpose registers are reconstructed here.
4012 */
4013
Ben Cheng1efc9c52009-06-08 18:25:27 -07004014/* Chaining cell for code that may need warmup. */
4015static void handleNormalChainingCell(CompilationUnit *cUnit,
4016 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004017{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004018 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4019 jitToInterpEntries.dvmJitToInterpNormal), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004020 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004021 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4022}
4023
4024/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07004025 * Chaining cell for instructions that immediately following already translated
4026 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07004027 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07004028static void handleHotChainingCell(CompilationUnit *cUnit,
4029 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004030{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004031 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4032 jitToInterpEntries.dvmJitToTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004033 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004034 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4035}
4036
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004037#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07004038/* Chaining cell for branches that branch back into the same basic block */
4039static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
4040 unsigned int offset)
4041{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004042#if defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07004043 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Jeff Hao97319a82009-08-12 16:57:15 -07004044 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004045#else
Bill Buzbee1465db52009-09-23 17:17:35 -07004046 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004047 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
4048#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07004049 newLIR1(cUnit, kThumbBlxR, r0);
Jeff Hao97319a82009-08-12 16:57:15 -07004050 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4051}
4052
4053#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004054/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07004055static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
4056 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004057{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004058 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4059 jitToInterpEntries.dvmJitToTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004060 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004061 addWordData(cUnit, (int) (callee->insns), true);
4062}
4063
Ben Cheng38329f52009-07-07 14:19:20 -07004064/* Chaining cell for monomorphic method invocations. */
4065static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
4066{
4067
4068 /* Should not be executed in the initial state */
4069 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
4070 /* To be filled: class */
4071 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
4072 /* To be filled: method */
4073 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
4074 /*
4075 * Rechain count. The initial value of 0 here will trigger chaining upon
4076 * the first invocation of this callsite.
4077 */
4078 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
4079}
4080
Ben Chengba4fc8b2009-06-01 13:00:29 -07004081/* Load the Dalvik PC into r0 and jump to the specified target */
4082static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004083 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004084{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004085 ArmLIR **pcrLabel =
4086 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004087 int numElems = cUnit->pcReconstructionList.numUsed;
4088 int i;
4089 for (i = 0; i < numElems; i++) {
4090 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
4091 /* r0 = dalvik PC */
4092 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
4093 genUnconditionalBranch(cUnit, targetLabel);
4094 }
4095}
4096
Bill Buzbee1465db52009-09-23 17:17:35 -07004097static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
4098 "kMirOpPhi",
4099 "kMirOpNullNRangeUpCheck",
4100 "kMirOpNullNRangeDownCheck",
4101 "kMirOpLowerBound",
4102 "kMirOpPunt",
Ben Cheng4238ec22009-08-24 16:32:22 -07004103};
4104
4105/*
4106 * vA = arrayReg;
4107 * vB = idxReg;
4108 * vC = endConditionReg;
4109 * arg[0] = maxC
4110 * arg[1] = minC
4111 * arg[2] = loopBranchConditionCode
4112 */
4113static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
4114{
Bill Buzbee1465db52009-09-23 17:17:35 -07004115 /*
4116 * NOTE: these synthesized blocks don't have ssa names assigned
4117 * for Dalvik registers. However, because they dominate the following
4118 * blocks we can simply use the Dalvik name w/ subscript 0 as the
4119 * ssa name.
4120 */
Ben Cheng4238ec22009-08-24 16:32:22 -07004121 DecodedInstruction *dInsn = &mir->dalvikInsn;
4122 const int lenOffset = offsetof(ArrayObject, length);
Ben Cheng4238ec22009-08-24 16:32:22 -07004123 const int maxC = dInsn->arg[0];
4124 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07004125 int regLength;
4126 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
4127 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
Ben Cheng4238ec22009-08-24 16:32:22 -07004128
4129 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07004130 rlArray = loadValue(cUnit, rlArray, kCoreReg);
4131 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
4132 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004133 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4134
4135 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07004136 regLength = allocTemp(cUnit);
4137 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07004138
4139 int delta = maxC;
4140 /*
4141 * If the loop end condition is ">=" instead of ">", then the largest value
4142 * of the index is "endCondition - 1".
4143 */
4144 if (dInsn->arg[2] == OP_IF_GE) {
4145 delta--;
4146 }
4147
4148 if (delta) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004149 int tReg = allocTemp(cUnit);
4150 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
4151 rlIdxEnd.lowReg = tReg;
4152 freeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004153 }
4154 /* Punt if "regIdxEnd < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004155 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07004156 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004157}
4158
4159/*
4160 * vA = arrayReg;
4161 * vB = idxReg;
4162 * vC = endConditionReg;
4163 * arg[0] = maxC
4164 * arg[1] = minC
4165 * arg[2] = loopBranchConditionCode
4166 */
4167static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
4168{
4169 DecodedInstruction *dInsn = &mir->dalvikInsn;
4170 const int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07004171 const int regLength = allocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07004172 const int maxC = dInsn->arg[0];
4173 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07004174 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
4175 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
Ben Cheng4238ec22009-08-24 16:32:22 -07004176
4177 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07004178 rlArray = loadValue(cUnit, rlArray, kCoreReg);
4179 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
4180 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004181 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4182
4183 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07004184 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07004185
4186 if (maxC) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004187 int tReg = allocTemp(cUnit);
4188 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
4189 rlIdxInit.lowReg = tReg;
4190 freeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004191 }
4192
4193 /* Punt if "regIdxInit < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004194 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07004195 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004196}
4197
4198/*
4199 * vA = idxReg;
4200 * vB = minC;
4201 */
4202static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
4203{
4204 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -07004205 const int minC = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07004206 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
Ben Cheng4238ec22009-08-24 16:32:22 -07004207
4208 /* regIdx <- initial index value */
Bill Buzbee1465db52009-09-23 17:17:35 -07004209 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004210
4211 /* Punt if "regIdxInit + minC >= 0" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004212 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004213 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4214}
4215
4216/* Extended MIR instructions like PHI */
4217static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
4218{
Bill Buzbee1465db52009-09-23 17:17:35 -07004219 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
Ben Cheng4238ec22009-08-24 16:32:22 -07004220 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
4221 false);
4222 strcpy(msg, extendedMIROpNames[opOffset]);
Bill Buzbee1465db52009-09-23 17:17:35 -07004223 newLIR1(cUnit, kArmPseudoExtended, (int) msg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004224
4225 switch (mir->dalvikInsn.opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004226 case kMirOpPhi: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004227 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07004228 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07004229 break;
4230 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004231 case kMirOpNullNRangeUpCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004232 genHoistedChecksForCountUpLoop(cUnit, mir);
4233 break;
4234 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004235 case kMirOpNullNRangeDownCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004236 genHoistedChecksForCountDownLoop(cUnit, mir);
4237 break;
4238 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004239 case kMirOpLowerBound: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004240 genHoistedLowerBoundCheck(cUnit, mir);
4241 break;
4242 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004243 case kMirOpPunt: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004244 genUnconditionalBranch(cUnit,
4245 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4246 break;
4247 }
4248 default:
4249 break;
4250 }
4251}
4252
4253/*
4254 * Create a PC-reconstruction cell for the starting offset of this trace.
4255 * Since the PCR cell is placed near the end of the compiled code which is
4256 * usually out of range for a conditional branch, we put two branches (one
4257 * branch over to the loop body and one layover branch to the actual PCR) at the
4258 * end of the entry block.
4259 */
4260static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
4261 ArmLIR *bodyLabel)
4262{
4263 /* Set up the place holder to reconstruct this Dalvik PC */
4264 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004265 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng4238ec22009-08-24 16:32:22 -07004266 pcrLabel->operands[0] =
4267 (int) (cUnit->method->insns + entry->startOffset);
4268 pcrLabel->operands[1] = entry->startOffset;
4269 /* Insert the place holder to the growable list */
4270 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
4271
4272 /*
4273 * Next, create two branches - one branch over to the loop body and the
4274 * other branch to the PCR cell to punt.
4275 */
4276 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004277 branchToBody->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07004278 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07004279 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07004280 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
4281
4282 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004283 branchToPCR->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07004284 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07004285 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004286 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
4287}
4288
Ben Chengba4fc8b2009-06-01 13:00:29 -07004289void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
4290{
4291 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004292 ArmLIR *labelList =
4293 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004294 GrowableList chainingListByType[kChainingCellLast];
Ben Chengba4fc8b2009-06-01 13:00:29 -07004295 int i;
4296
4297 /*
Ben Cheng38329f52009-07-07 14:19:20 -07004298 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07004299 */
Bill Buzbee1465db52009-09-23 17:17:35 -07004300 for (i = 0; i < kChainingCellLast; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004301 dvmInitGrowableList(&chainingListByType[i], 2);
4302 }
4303
4304 BasicBlock **blockList = cUnit->blockList;
4305
Bill Buzbee6e963e12009-06-17 16:56:19 -07004306 if (cUnit->executionCount) {
4307 /*
4308 * Reserve 6 bytes at the beginning of the trace
4309 * +----------------------------+
4310 * | execution count (4 bytes) |
4311 * +----------------------------+
4312 * | chain cell offset (2 bytes)|
4313 * +----------------------------+
4314 * ...and then code to increment the execution
4315 * count:
4316 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
4317 * sub r0, #10 @ back up to addr of executionCount
4318 * ldr r1, [r0]
4319 * add r1, #1
4320 * str r1, [r0]
4321 */
Bill Buzbee1465db52009-09-23 17:17:35 -07004322 newLIR1(cUnit, kArm16BitData, 0);
4323 newLIR1(cUnit, kArm16BitData, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07004324 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004325 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004326 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07004327 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee1465db52009-09-23 17:17:35 -07004328 newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
4329 newLIR2(cUnit, kThumbSubRI8, r0, 10);
4330 newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
4331 newLIR2(cUnit, kThumbAddRI8, r1, 1);
4332 newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004333 } else {
4334 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07004335 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004336 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004337 cUnit->headerSize = 2;
4338 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07004339
Ben Chengba4fc8b2009-06-01 13:00:29 -07004340 /* Handle the content in each basic block */
4341 for (i = 0; i < cUnit->numBlocks; i++) {
4342 blockList[i]->visited = true;
4343 MIR *mir;
4344
4345 labelList[i].operands[0] = blockList[i]->startOffset;
4346
Bill Buzbee1465db52009-09-23 17:17:35 -07004347 if (blockList[i]->blockType >= kChainingCellLast) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004348 /*
4349 * Append the label pseudo LIR first. Chaining cells will be handled
4350 * separately afterwards.
4351 */
4352 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
4353 }
4354
Bill Buzbee1465db52009-09-23 17:17:35 -07004355 if (blockList[i]->blockType == kEntryBlock) {
4356 labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07004357 if (blockList[i]->firstMIRInsn == NULL) {
4358 continue;
4359 } else {
4360 setupLoopEntryBlock(cUnit, blockList[i],
4361 &labelList[blockList[i]->fallThrough->id]);
4362 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004363 } else if (blockList[i]->blockType == kExitBlock) {
4364 labelList[i].opCode = ARM_PSEUDO_kExitBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07004365 goto gen_fallthrough;
Bill Buzbee1465db52009-09-23 17:17:35 -07004366 } else if (blockList[i]->blockType == kDalvikByteCode) {
4367 labelList[i].opCode = kArmPseudoNormalBlockLabel;
Ben Chenge9695e52009-06-16 16:11:47 -07004368 /* Reset the register state */
Bill Buzbee1465db52009-09-23 17:17:35 -07004369 resetRegPool(cUnit);
4370 clobberAllRegs(cUnit);
4371 resetNullCheckTracker(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004372 } else {
4373 switch (blockList[i]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004374 case kChainingCellNormal:
4375 labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004376 /* handle the codegen later */
4377 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004378 &chainingListByType[kChainingCellNormal], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004379 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004380 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07004381 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004382 ARM_PSEUDO_kChainingCellInvokeSingleton;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004383 labelList[i].operands[0] =
4384 (int) blockList[i]->containingMethod;
4385 /* handle the codegen later */
4386 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004387 &chainingListByType[kChainingCellInvokeSingleton],
Ben Cheng38329f52009-07-07 14:19:20 -07004388 (void *) i);
4389 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004390 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07004391 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004392 ARM_PSEUDO_kChainingCellInvokePredicted;
Ben Cheng38329f52009-07-07 14:19:20 -07004393 /* handle the codegen later */
4394 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004395 &chainingListByType[kChainingCellInvokePredicted],
Ben Cheng38329f52009-07-07 14:19:20 -07004396 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004397 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004398 case kChainingCellHot:
Ben Chengba4fc8b2009-06-01 13:00:29 -07004399 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004400 ARM_PSEUDO_kChainingCellHot;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004401 /* handle the codegen later */
4402 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004403 &chainingListByType[kChainingCellHot],
Ben Chengba4fc8b2009-06-01 13:00:29 -07004404 (void *) i);
4405 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004406 case kPCReconstruction:
Ben Chengba4fc8b2009-06-01 13:00:29 -07004407 /* Make sure exception handling block is next */
4408 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004409 ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004410 assert (i == cUnit->numBlocks - 2);
4411 handlePCReconstruction(cUnit, &labelList[i+1]);
4412 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004413 case kExceptionHandling:
4414 labelList[i].opCode = kArmPseudoEHBlockLabel;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004415 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07004416 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4417 jitToInterpEntries.dvmJitToInterpPunt),
4418 r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07004419 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004420 }
4421 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004422#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07004423 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07004424 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004425 ARM_PSEUDO_kChainingCellBackwardBranch;
Jeff Hao97319a82009-08-12 16:57:15 -07004426 /* handle the codegen later */
4427 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004428 &chainingListByType[kChainingCellBackwardBranch],
Jeff Hao97319a82009-08-12 16:57:15 -07004429 (void *) i);
4430 break;
4431#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004432 default:
4433 break;
4434 }
4435 continue;
4436 }
Ben Chenge9695e52009-06-16 16:11:47 -07004437
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004438 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07004439
Ben Chengba4fc8b2009-06-01 13:00:29 -07004440 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004441
4442 resetRegPool(cUnit);
4443 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
4444 clobberAllRegs(cUnit);
4445 }
4446
4447 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
4448 resetDefTracking(cUnit);
4449 }
4450
4451 if (mir->dalvikInsn.opCode >= kMirOpFirst) {
Ben Cheng4238ec22009-08-24 16:32:22 -07004452 handleExtendedMIR(cUnit, mir);
4453 continue;
4454 }
4455
Bill Buzbee1465db52009-09-23 17:17:35 -07004456
Ben Chengba4fc8b2009-06-01 13:00:29 -07004457 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
4458 InstructionFormat dalvikFormat =
4459 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004460 ArmLIR *boundaryLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004461 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
Ben Chengccd6c012009-10-15 14:52:45 -07004462 mir->offset,
4463 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
4464 );
Ben Cheng4238ec22009-08-24 16:32:22 -07004465 if (mir->ssaRep) {
4466 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07004467 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07004468 }
4469
Ben Chenge9695e52009-06-16 16:11:47 -07004470 /* Remember the first LIR for this block */
4471 if (headLIR == NULL) {
4472 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07004473 /* Set the first boundaryLIR as a scheduling barrier */
4474 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07004475 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004476
Ben Chengba4fc8b2009-06-01 13:00:29 -07004477 bool notHandled;
4478 /*
4479 * Debugging: screen the opcode first to see if it is in the
4480 * do[-not]-compile list
4481 */
4482 bool singleStepMe =
4483 gDvmJit.includeSelectedOp !=
4484 ((gDvmJit.opList[dalvikOpCode >> 3] &
4485 (1 << (dalvikOpCode & 0x7))) !=
4486 0);
Jeff Hao97319a82009-08-12 16:57:15 -07004487#if defined(WITH_SELF_VERIFICATION)
4488 /* Punt on opcodes we can't replay */
4489 if (selfVerificationPuntOps(dalvikOpCode))
4490 singleStepMe = true;
4491#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004492 if (singleStepMe || cUnit->allSingleStep) {
4493 notHandled = false;
4494 genInterpSingleStep(cUnit, mir);
4495 } else {
4496 opcodeCoverage[dalvikOpCode]++;
4497 switch (dalvikFormat) {
4498 case kFmt10t:
4499 case kFmt20t:
4500 case kFmt30t:
4501 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4502 mir, blockList[i], labelList);
4503 break;
4504 case kFmt10x:
4505 notHandled = handleFmt10x(cUnit, mir);
4506 break;
4507 case kFmt11n:
4508 case kFmt31i:
4509 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4510 break;
4511 case kFmt11x:
4512 notHandled = handleFmt11x(cUnit, mir);
4513 break;
4514 case kFmt12x:
4515 notHandled = handleFmt12x(cUnit, mir);
4516 break;
4517 case kFmt20bc:
4518 notHandled = handleFmt20bc(cUnit, mir);
4519 break;
4520 case kFmt21c:
4521 case kFmt31c:
4522 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4523 break;
4524 case kFmt21h:
4525 notHandled = handleFmt21h(cUnit, mir);
4526 break;
4527 case kFmt21s:
4528 notHandled = handleFmt21s(cUnit, mir);
4529 break;
4530 case kFmt21t:
4531 notHandled = handleFmt21t(cUnit, mir, blockList[i],
4532 labelList);
4533 break;
4534 case kFmt22b:
4535 case kFmt22s:
4536 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4537 break;
4538 case kFmt22c:
4539 notHandled = handleFmt22c(cUnit, mir);
4540 break;
4541 case kFmt22cs:
4542 notHandled = handleFmt22cs(cUnit, mir);
4543 break;
4544 case kFmt22t:
4545 notHandled = handleFmt22t(cUnit, mir, blockList[i],
4546 labelList);
4547 break;
4548 case kFmt22x:
4549 case kFmt32x:
4550 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4551 break;
4552 case kFmt23x:
4553 notHandled = handleFmt23x(cUnit, mir);
4554 break;
4555 case kFmt31t:
4556 notHandled = handleFmt31t(cUnit, mir);
4557 break;
4558 case kFmt3rc:
4559 case kFmt35c:
4560 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4561 labelList);
4562 break;
4563 case kFmt3rms:
4564 case kFmt35ms:
4565 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4566 labelList);
4567 break;
4568 case kFmt3inline:
4569 notHandled = handleFmt3inline(cUnit, mir);
4570 break;
4571 case kFmt51l:
4572 notHandled = handleFmt51l(cUnit, mir);
4573 break;
4574 default:
4575 notHandled = true;
4576 break;
4577 }
4578 }
4579 if (notHandled) {
4580 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4581 mir->offset,
4582 dalvikOpCode, getOpcodeName(dalvikOpCode),
4583 dalvikFormat);
4584 dvmAbort();
4585 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004586 }
4587 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004588
Bill Buzbee1465db52009-09-23 17:17:35 -07004589 if (blockList[i]->blockType == kEntryBlock) {
Ben Cheng4238ec22009-08-24 16:32:22 -07004590 dvmCompilerAppendLIR(cUnit,
4591 (LIR *) cUnit->loopAnalysis->branchToBody);
4592 dvmCompilerAppendLIR(cUnit,
4593 (LIR *) cUnit->loopAnalysis->branchToPCR);
4594 }
4595
4596 if (headLIR) {
4597 /*
4598 * Eliminate redundant loads/stores and delay stores into later
4599 * slots
4600 */
4601 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4602 cUnit->lastLIRInsn);
4603 }
4604
4605gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004606 /*
4607 * Check if the block is terminated due to trace length constraint -
4608 * insert an unconditional branch to the chaining cell.
4609 */
4610 if (blockList[i]->needFallThroughBranch) {
4611 genUnconditionalBranch(cUnit,
4612 &labelList[blockList[i]->fallThrough->id]);
4613 }
4614
Ben Chengba4fc8b2009-06-01 13:00:29 -07004615 }
4616
Ben Chenge9695e52009-06-16 16:11:47 -07004617 /* Handle the chaining cells in predefined order */
Bill Buzbee1465db52009-09-23 17:17:35 -07004618 for (i = 0; i < kChainingCellLast; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004619 size_t j;
4620 int *blockIdList = (int *) chainingListByType[i].elemList;
4621
4622 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4623
4624 /* No chaining cells of this type */
4625 if (cUnit->numChainingCells[i] == 0)
4626 continue;
4627
4628 /* Record the first LIR for a new type of chaining cell */
4629 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4630
4631 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4632 int blockId = blockIdList[j];
4633
4634 /* Align this chaining cell first */
Bill Buzbee1465db52009-09-23 17:17:35 -07004635 newLIR0(cUnit, kArmPseudoPseudoAlign4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004636
4637 /* Insert the pseudo chaining instruction */
4638 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4639
4640
4641 switch (blockList[blockId]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004642 case kChainingCellNormal:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004643 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004644 blockList[blockId]->startOffset);
4645 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004646 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07004647 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004648 blockList[blockId]->containingMethod);
4649 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004650 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07004651 handleInvokePredictedChainingCell(cUnit);
4652 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004653 case kChainingCellHot:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004654 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004655 blockList[blockId]->startOffset);
4656 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004657#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07004658 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07004659 handleBackwardBranchChainingCell(cUnit,
4660 blockList[blockId]->startOffset);
4661 break;
4662#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004663 default:
Bill Buzbee1465db52009-09-23 17:17:35 -07004664 LOGE("Bad blocktype %d", blockList[blockId]->blockType);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004665 dvmAbort();
4666 break;
4667 }
4668 }
4669 }
Ben Chenge9695e52009-06-16 16:11:47 -07004670
Ben Cheng6c10a972009-10-29 14:39:18 -07004671 /*
4672 * Generate the branch to the dvmJitToInterpNoChain entry point at the end
4673 * of all chaining cells for the overflow cases.
4674 */
4675 if (cUnit->switchOverflowPad) {
4676 loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
4677 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4678 jitToInterpEntries.dvmJitToInterpNoChain), r2);
4679 opRegReg(cUnit, kOpAdd, r1, r1);
4680 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
4681#if defined(EXIT_STATS)
4682 loadConstant(cUnit, r0, kSwitchOverflow);
4683#endif
4684 opReg(cUnit, kOpBlx, r2);
4685 }
4686
Ben Chenge9695e52009-06-16 16:11:47 -07004687 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004688}
4689
4690/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004691bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004692{
Ben Chengccd6c012009-10-15 14:52:45 -07004693 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004694
Ben Chengccd6c012009-10-15 14:52:45 -07004695 if (gDvmJit.codeCacheFull) {
4696 return false;
4697 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07004698
Ben Chengccd6c012009-10-15 14:52:45 -07004699 switch (work->kind) {
4700 case kWorkOrderMethod:
4701 res = dvmCompileMethod(work->info, &work->result);
4702 break;
4703 case kWorkOrderTrace:
4704 /* Start compilation with maximally allowed trace length */
4705 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
4706 break;
4707 case kWorkOrderTraceDebug: {
4708 bool oldPrintMe = gDvmJit.printMe;
4709 gDvmJit.printMe = true;
4710 /* Start compilation with maximally allowed trace length */
4711 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
4712 gDvmJit.printMe = oldPrintMe;;
4713 break;
4714 }
4715 default:
4716 res = false;
4717 dvmAbort();
4718 }
4719 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004720}
4721
Ben Chengba4fc8b2009-06-01 13:00:29 -07004722/* Architectural-specific debugging helpers go here */
4723void dvmCompilerArchDump(void)
4724{
4725 /* Print compiled opcode in this VM instance */
4726 int i, start, streak;
4727 char buf[1024];
4728
4729 streak = i = 0;
4730 buf[0] = 0;
4731 while (opcodeCoverage[i] == 0 && i < 256) {
4732 i++;
4733 }
4734 if (i == 256) {
4735 return;
4736 }
4737 for (start = i++, streak = 1; i < 256; i++) {
4738 if (opcodeCoverage[i]) {
4739 streak++;
4740 } else {
4741 if (streak == 1) {
4742 sprintf(buf+strlen(buf), "%x,", start);
4743 } else {
4744 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4745 }
4746 streak = 0;
4747 while (opcodeCoverage[i] == 0 && i < 256) {
4748 i++;
4749 }
4750 if (i < 256) {
4751 streak = 1;
4752 start = i;
4753 }
4754 }
4755 }
4756 if (streak) {
4757 if (streak == 1) {
4758 sprintf(buf+strlen(buf), "%x", start);
4759 } else {
4760 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4761 }
4762 }
4763 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004764 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004765 }
4766}
Ben Chengd7d426a2009-09-22 11:23:36 -07004767
4768/* Common initialization routine for an architecture family */
4769bool dvmCompilerArchInit()
4770{
4771 int i;
4772
Bill Buzbee1465db52009-09-23 17:17:35 -07004773 for (i = 0; i < kArmLast; i++) {
Ben Chengd7d426a2009-09-22 11:23:36 -07004774 if (EncodingMap[i].opCode != i) {
4775 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4776 EncodingMap[i].name, i, EncodingMap[i].opCode);
4777 dvmAbort();
4778 }
4779 }
4780
4781 return compilerArchVariantInit();
4782}