blob: 30a7b1b8c718bdc87cc4d80dd27a24d52bbb1fee [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{
59 int reg = heapArgSpace->regMap & 0xF;
60
61 switch (reg) {
62 case 0:
63 *addr = heapArgSpace->r0;
64 break;
65 case 1:
66 *addr = heapArgSpace->r1;
67 break;
68 case 2:
69 *addr = heapArgSpace->r2;
70 break;
71 case 3:
72 *addr = heapArgSpace->r3;
73 break;
74 default:
75 LOGE("ERROR: bad reg used in selfVerificationLoadDecode: %d", reg);
76 break;
77 }
78}
79
80/* Decode contents of heapArgSpace to determine reg to load into */
81static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
82 int data, int reg)
83{
84 switch (reg) {
85 case 0:
86 heapArgSpace->r0 = data;
87 break;
88 case 1:
89 heapArgSpace->r1 = data;
90 break;
91 case 2:
92 heapArgSpace->r2 = data;
93 break;
94 case 3:
95 heapArgSpace->r3 = data;
96 break;
97 default:
98 LOGE("ERROR: bad reg passed to selfVerificationLoadDecodeData: %d",
99 reg);
100 break;
101 }
102}
103
104static void selfVerificationLoad(InterpState* interpState)
105{
106 Thread *self = dvmThreadSelf();
107 ShadowHeap *heapSpacePtr;
108 ShadowSpace *shadowSpace = self->shadowSpace;
109 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
110
111 int addr, data;
112 selfVerificationLoadDecode(heapArgSpace, &addr);
113
114 for (heapSpacePtr = shadowSpace->heapSpace;
115 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
116 if (heapSpacePtr->addr == addr) {
117 data = heapSpacePtr->data;
118 break;
119 }
120 }
121
122 if (heapSpacePtr == shadowSpace->heapSpaceTail)
123 data = *((unsigned int*) addr);
124
Jeff Hao97319a82009-08-12 16:57:15 -0700125 int reg = (heapArgSpace->regMap >> 4) & 0xF;
Ben Chengd7d426a2009-09-22 11:23:36 -0700126
127 //LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
128
Jeff Hao97319a82009-08-12 16:57:15 -0700129 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
130}
131
132static void selfVerificationLoadByte(InterpState* interpState)
133{
134 Thread *self = dvmThreadSelf();
135 ShadowHeap *heapSpacePtr;
136 ShadowSpace *shadowSpace = self->shadowSpace;
137 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
138
139 int addr, data;
140 selfVerificationLoadDecode(heapArgSpace, &addr);
141
142 int maskedAddr = addr & 0xFFFFFFFC;
143 int alignment = addr & 0x3;
144
145 for (heapSpacePtr = shadowSpace->heapSpace;
146 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
147 if (heapSpacePtr->addr == maskedAddr) {
148 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
149 data = *((unsigned char*) addr);
150 break;
151 }
152 }
153
154 if (heapSpacePtr == shadowSpace->heapSpaceTail)
155 data = *((unsigned char*) addr);
156
157 //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
158
159 int reg = (heapArgSpace->regMap >> 4) & 0xF;
160 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
161}
162
163static void selfVerificationLoadHalfword(InterpState* interpState)
164{
165 Thread *self = dvmThreadSelf();
166 ShadowHeap *heapSpacePtr;
167 ShadowSpace *shadowSpace = self->shadowSpace;
168 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
169
170 int addr, data;
171 selfVerificationLoadDecode(heapArgSpace, &addr);
172
173 int maskedAddr = addr & 0xFFFFFFFC;
174 int alignment = addr & 0x2;
175
176 for (heapSpacePtr = shadowSpace->heapSpace;
177 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
178 if (heapSpacePtr->addr == maskedAddr) {
179 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
180 data = *((unsigned short*) addr);
181 break;
182 }
183 }
184
185 if (heapSpacePtr == shadowSpace->heapSpaceTail)
186 data = *((unsigned short*) addr);
187
188 //LOGD("*** HEAP LOAD HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
189
190 int reg = (heapArgSpace->regMap >> 4) & 0xF;
191 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
192}
193
194static void selfVerificationLoadSignedByte(InterpState* interpState)
195{
196 Thread *self = dvmThreadSelf();
197 ShadowHeap* heapSpacePtr;
198 ShadowSpace* shadowSpace = self->shadowSpace;
199 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
200
201 int addr, data;
202 selfVerificationLoadDecode(heapArgSpace, &addr);
203
204 int maskedAddr = addr & 0xFFFFFFFC;
205 int alignment = addr & 0x3;
206
207 for (heapSpacePtr = shadowSpace->heapSpace;
208 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
209 if (heapSpacePtr->addr == maskedAddr) {
210 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
211 data = *((signed char*) addr);
212 break;
213 }
214 }
215
216 if (heapSpacePtr == shadowSpace->heapSpaceTail)
217 data = *((signed char*) addr);
218
219 //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
220
221 int reg = (heapArgSpace->regMap >> 4) & 0xF;
222 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
223}
224
225static void selfVerificationLoadSignedHalfword(InterpState* interpState)
226{
227 Thread *self = dvmThreadSelf();
228 ShadowHeap* heapSpacePtr;
229 ShadowSpace* shadowSpace = self->shadowSpace;
230 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
231
232 int addr, data;
233 selfVerificationLoadDecode(heapArgSpace, &addr);
234
235 int maskedAddr = addr & 0xFFFFFFFC;
236 int alignment = addr & 0x2;
237
238 for (heapSpacePtr = shadowSpace->heapSpace;
239 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
240 if (heapSpacePtr->addr == maskedAddr) {
241 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
242 data = *((signed short*) addr);
243 break;
244 }
245 }
246
247 if (heapSpacePtr == shadowSpace->heapSpaceTail)
248 data = *((signed short*) addr);
249
250 //LOGD("*** HEAP LOAD SIGNED HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
251
252 int reg = (heapArgSpace->regMap >> 4) & 0xF;
253 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
254}
255
256static void selfVerificationLoadDoubleword(InterpState* interpState)
257{
258 Thread *self = dvmThreadSelf();
259 ShadowHeap* heapSpacePtr;
260 ShadowSpace* shadowSpace = self->shadowSpace;
261 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
262
263 int addr;
264 selfVerificationLoadDecode(heapArgSpace, &addr);
265
266 int addr2 = addr+4;
267 unsigned int data = *((unsigned int*) addr);
268 unsigned int data2 = *((unsigned int*) addr2);
269
270 for (heapSpacePtr = shadowSpace->heapSpace;
271 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
272 if (heapSpacePtr->addr == addr) {
273 data = heapSpacePtr->data;
274 } else if (heapSpacePtr->addr == addr2) {
275 data2 = heapSpacePtr->data;
276 }
277 }
278
279 //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
280 // addr, data, data2);
281
282 int reg = (heapArgSpace->regMap >> 4) & 0xF;
283 int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
284 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
285 selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
286}
287
288/* Decode contents of heapArgSpace to determine arguments to store. */
289static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
290 int* value, int reg)
291{
292 switch (reg) {
293 case 0:
294 *value = heapArgSpace->r0;
295 break;
296 case 1:
297 *value = heapArgSpace->r1;
298 break;
299 case 2:
300 *value = heapArgSpace->r2;
301 break;
302 case 3:
303 *value = heapArgSpace->r3;
304 break;
305 default:
306 LOGE("ERROR: bad reg passed to selfVerificationStoreDecode: %d",
307 reg);
308 break;
309 }
310}
311
312static void selfVerificationStore(InterpState* interpState)
313{
314 Thread *self = dvmThreadSelf();
315 ShadowHeap *heapSpacePtr;
316 ShadowSpace *shadowSpace = self->shadowSpace;
317 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
318
319 int addr, data;
320 int reg0 = heapArgSpace->regMap & 0xF;
321 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
322 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
323 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
324
325 //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
326
327 for (heapSpacePtr = shadowSpace->heapSpace;
328 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
329 if (heapSpacePtr->addr == addr) break;
330 }
331
332 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
333 heapSpacePtr->addr = addr;
334 shadowSpace->heapSpaceTail++;
335 }
336
337 heapSpacePtr->data = data;
338}
339
340static void selfVerificationStoreByte(InterpState* interpState)
341{
342 Thread *self = dvmThreadSelf();
343 ShadowHeap *heapSpacePtr;
344 ShadowSpace *shadowSpace = self->shadowSpace;
345 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
346
347 int addr, data;
348 int reg0 = heapArgSpace->regMap & 0xF;
349 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
350 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
351 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
352
353 int maskedAddr = addr & 0xFFFFFFFC;
354 int alignment = addr & 0x3;
355
356 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
357
358 for (heapSpacePtr = shadowSpace->heapSpace;
359 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
360 if (heapSpacePtr->addr == maskedAddr) break;
361 }
362
363 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
364 heapSpacePtr->addr = maskedAddr;
365 heapSpacePtr->data = *((unsigned int*) maskedAddr);
366 shadowSpace->heapSpaceTail++;
367 }
368
369 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
370 *((unsigned char*) addr) = (char) data;
371
372 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
373 // addr, heapSpacePtr->data);
374}
375
376static void selfVerificationStoreHalfword(InterpState* interpState)
377{
378 Thread *self = dvmThreadSelf();
379 ShadowHeap *heapSpacePtr;
380 ShadowSpace *shadowSpace = self->shadowSpace;
381 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
382
383 int addr, data;
384 int reg0 = heapArgSpace->regMap & 0xF;
385 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
386 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
387 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
388
389 int maskedAddr = addr & 0xFFFFFFFC;
390 int alignment = addr & 0x2;
391
392 //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
393
394 for (heapSpacePtr = shadowSpace->heapSpace;
395 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
396 if (heapSpacePtr->addr == maskedAddr) break;
397 }
398
399 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
400 heapSpacePtr->addr = maskedAddr;
401 heapSpacePtr->data = *((unsigned int*) maskedAddr);
402 shadowSpace->heapSpaceTail++;
403 }
404
405 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
406 *((unsigned short*) addr) = (short) data;
407
408 //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Final Data: 0x%x",
409 // addr, heapSpacePtr->data);
410}
411
412static void selfVerificationStoreDoubleword(InterpState* interpState)
413{
414 Thread *self = dvmThreadSelf();
415 ShadowHeap *heapSpacePtr;
416 ShadowSpace *shadowSpace = self->shadowSpace;
417 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
418
419 int addr, data, data2;
420 int reg0 = heapArgSpace->regMap & 0xF;
421 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
422 int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
423 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
424 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
425 selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
426
427 int addr2 = addr+4;
428 bool store1 = false, store2 = false;
429
430 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
431 // addr, data, data2);
432
433 for (heapSpacePtr = shadowSpace->heapSpace;
434 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
435 if (heapSpacePtr->addr == addr) {
436 heapSpacePtr->data = data;
437 store1 = true;
438 } else if (heapSpacePtr->addr == addr2) {
439 heapSpacePtr->data = data2;
440 store2 = true;
441 }
442 }
443
444 if (!store1) {
445 shadowSpace->heapSpaceTail->addr = addr;
446 shadowSpace->heapSpaceTail->data = data;
447 shadowSpace->heapSpaceTail++;
448 }
449 if (!store2) {
450 shadowSpace->heapSpaceTail->addr = addr2;
451 shadowSpace->heapSpaceTail->data = data2;
452 shadowSpace->heapSpaceTail++;
453 }
454}
455
456/* Common wrapper function for all memory operations */
457static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
458 void* funct)
459{
460 int regMask = (1 << r4PC) | (1 << r3) | (1 << r2) | (1 << r1) | (1 << r0);
461
462 /* r7 <- InterpState->heapArgSpace */
463 loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
464 newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
465
466 /* Save out values to heapArgSpace */
467 loadConstant(cUnit, r4PC, regMap);
468 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
469
470 /* Pass interpState pointer to function */
471 newLIR2(cUnit, THUMB_MOV_RR, r0, rGLUE);
472
473 /* Set function pointer and branch */
474 loadConstant(cUnit, r1, (int) funct);
475 newLIR1(cUnit, THUMB_BLX_R, r1);
476
477 /* r7 <- InterpState->heapArgSpace */
478 loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
479 newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
480
481 /* Restore register state */
482 newLIR2(cUnit, THUMB_LDMIA, r7, regMask);
483}
484#endif
485
Ben Chengba4fc8b2009-06-01 13:00:29 -0700486/*
Ben Chengd7d426a2009-09-22 11:23:36 -0700487 * Mark load/store instructions that access Dalvik registers through rFP +
488 * offset.
489 */
490static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
491{
492 if (isLoad) {
493 lir->useMask |= ENCODE_DALVIK_REG;
494 } else {
495 lir->defMask |= ENCODE_DALVIK_REG;
496 }
497
498 /*
499 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
500 * access.
501 */
502 lir->aliasInfo = regId;
503 if (DOUBLEREG(lir->operands[0])) {
504 lir->aliasInfo |= 0x80000000;
505 }
506}
507
508/*
509 * Decode the register id and mark the corresponding bit(s).
510 */
511static inline void setupRegMask(u8 *mask, int reg)
512{
513 u8 seed;
514 int shift;
515 int regId = reg & 0x1f;
516
517 /*
518 * Each double register is equal to a pair of single-precision FP registers
519 */
520 seed = DOUBLEREG(reg) ? 3 : 1;
521 /* FP register starts at bit position 16 */
522 shift = FPREG(reg) ? kFPReg0 : 0;
523 /* Expand the double register id into single offset */
524 shift += regId;
525 *mask |= seed << shift;
526}
527
528/*
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700529 * Set up the proper fields in the resource mask
530 */
531static void setupResourceMasks(ArmLIR *lir)
532{
533 int opCode = lir->opCode;
534 int flags;
535
536 if (opCode <= 0) {
537 lir->useMask = lir->defMask = 0;
538 return;
539 }
540
541 flags = EncodingMap[lir->opCode].flags;
542
543 /* Set up the mask for resources that are updated */
544 if (flags & IS_BRANCH) {
545 lir->defMask |= ENCODE_REG_PC;
Ben Chengd7d426a2009-09-22 11:23:36 -0700546 lir->useMask |= ENCODE_REG_PC;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700547 }
548
549 if (flags & REG_DEF0) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700550 setupRegMask(&lir->defMask, lir->operands[0]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700551 }
552
553 if (flags & REG_DEF1) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700554 setupRegMask(&lir->defMask, lir->operands[1]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700555 }
556
557 if (flags & REG_DEF_SP) {
558 lir->defMask |= ENCODE_REG_SP;
559 }
560
Ben Chengd7d426a2009-09-22 11:23:36 -0700561 if (flags & REG_DEF_SP) {
562 lir->defMask |= ENCODE_REG_LR;
563 }
564
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700565 if (flags & REG_DEF_LIST0) {
566 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
567 }
568
569 if (flags & REG_DEF_LIST1) {
570 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
571 }
572
573 if (flags & SETS_CCODES) {
574 lir->defMask |= ENCODE_CCODE;
575 }
576
577 /* Conservatively treat the IT block */
578 if (flags & IS_IT) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700579 lir->defMask = ENCODE_ALL;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700580 }
581
582 /* Set up the mask for resources that are used */
583 if (flags & IS_BRANCH) {
584 lir->useMask |= ENCODE_REG_PC;
585 }
586
587 if (flags & (REG_USE0 | REG_USE1 | REG_USE2)) {
588 int i;
589
590 for (i = 0; i < 3; i++) {
591 if (flags & (1 << (kRegUse0 + i))) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700592 setupRegMask(&lir->useMask, lir->operands[i]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700593 }
594 }
595 }
596
597 if (flags & REG_USE_PC) {
598 lir->useMask |= ENCODE_REG_PC;
599 }
600
601 if (flags & REG_USE_SP) {
602 lir->useMask |= ENCODE_REG_SP;
603 }
604
605 if (flags & REG_USE_LIST0) {
606 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
607 }
608
609 if (flags & REG_USE_LIST1) {
610 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
611 }
612
613 if (flags & USES_CCODES) {
614 lir->useMask |= ENCODE_CCODE;
615 }
616}
617
618/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700619 * The following are building blocks to construct low-level IRs with 0 - 4
Ben Chengba4fc8b2009-06-01 13:00:29 -0700620 * operands.
621 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700622static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700623{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700624 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700625 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700626 insn->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700627 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700628 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
629 return insn;
630}
631
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700632static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700633 int dest)
634{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700635 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700636 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700637 insn->opCode = opCode;
638 insn->operands[0] = dest;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700639 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700640 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
641 return insn;
642}
643
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700644static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700645 int dest, int src1)
646{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700647 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700648 assert(isPseudoOpCode(opCode) ||
649 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700650 insn->opCode = opCode;
651 insn->operands[0] = dest;
652 insn->operands[1] = src1;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700653 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700654 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
655 return insn;
656}
657
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700658static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700659 int dest, int src1, int src2)
660{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700661 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700662 assert(isPseudoOpCode(opCode) ||
663 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700664 insn->opCode = opCode;
665 insn->operands[0] = dest;
666 insn->operands[1] = src1;
667 insn->operands[2] = src2;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700668 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700669 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
670 return insn;
671}
672
Bill Buzbee270c1d62009-08-13 16:58:07 -0700673static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
674 int dest, int src1, int src2, int info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700675{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700676 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
677 assert(isPseudoOpCode(opCode) ||
678 (EncodingMap[opCode].flags & IS_QUAD_OP));
679 insn->opCode = opCode;
680 insn->operands[0] = dest;
681 insn->operands[1] = src1;
682 insn->operands[2] = src2;
683 insn->operands[3] = info;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700684 setupResourceMasks(insn);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700685 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
686 return insn;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700687}
688
Ben Chengba4fc8b2009-06-01 13:00:29 -0700689/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700690 * If the next instruction is a move-result or move-result-long,
691 * return the target Dalvik instruction and convert the next to a
692 * nop. Otherwise, return -1. Used to optimize method inlining.
693 */
694static int inlinedTarget(MIR *mir)
695{
696 if (mir->next &&
697 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
698 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT) ||
699 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE))) {
700 mir->next->dalvikInsn.opCode = OP_NOP;
701 return mir->next->dalvikInsn.vA;
702 } else {
703 return -1;
704 }
705}
706
707
708
709/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700710 * The following are building blocks to insert constants into the pool or
711 * instruction streams.
712 */
713
714/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700715static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700716{
717 /* Add the constant to the literal pool */
718 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700719 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700720 newValue->operands[0] = value;
721 newValue->generic.next = cUnit->wordList;
722 cUnit->wordList = (LIR *) newValue;
723 return newValue;
724 } else {
725 /* Add the constant in the middle of code stream */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700726 newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
727 newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700728 }
729 return NULL;
730}
731
732/*
733 * Search the existing constants in the literal pool for an exact or close match
734 * within specified delta (greater or equal to 0).
735 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700736static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700737 unsigned int delta)
738{
739 LIR *dataTarget = cUnit->wordList;
740 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700741 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700742 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700743 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700744 dataTarget = dataTarget->next;
745 }
746 return NULL;
747}
748
Ben Chengd7d426a2009-09-22 11:23:36 -0700749/*
750 * Generate an ARM_PSEUDO_BARRIER marker to indicate the boundary of special
751 * blocks.
752 */
753static void genBarrier(CompilationUnit *cUnit)
754{
755 ArmLIR *barrier = newLIR0(cUnit, ARM_PSEUDO_BARRIER);
756 /* Mark all resources as being clobbered */
757 barrier->defMask = -1;
758}
759
Ben Chengba4fc8b2009-06-01 13:00:29 -0700760/* Perform the actual operation for OP_RETURN_* */
761static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
762{
763 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
764#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700765 gDvmJit.returnOp++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700766#endif
767 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700768 /* Insert branch, but defer setting of target */
769 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700770 /* Set up the place holder to reconstruct this Dalvik PC */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700771 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
772 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700773 pcrLabel->operands[0] = dPC;
774 pcrLabel->operands[1] = mir->offset;
775 /* Insert the place holder to the growable list */
776 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
777 /* Branch to the PC reconstruction code */
778 branch->generic.target = (LIR *) pcrLabel;
779}
780
Ben Chengba4fc8b2009-06-01 13:00:29 -0700781/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700782static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
783 ArmLIR *branch,
784 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700785{
786 /* Set up the place holder to reconstruct this Dalvik PC */
787 if (pcrLabel == NULL) {
788 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700789 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
790 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700791 pcrLabel->operands[0] = dPC;
792 pcrLabel->operands[1] = dOffset;
793 /* Insert the place holder to the growable list */
794 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
795 }
796 /* Branch to the PC reconstruction code */
797 branch->generic.target = (LIR *) pcrLabel;
798 return pcrLabel;
799}
800
Ben Chengba4fc8b2009-06-01 13:00:29 -0700801
802/*
803 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
804 * satisfies.
805 */
Ben Cheng0fd31e42009-09-03 14:40:16 -0700806static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
807 ArmConditionCode cond,
808 int reg1, int reg2, int dOffset,
809 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700810{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700811 ArmLIR *res;
812 res = opRegReg(cUnit, OP_CMP, reg1, reg2);
Ben Cheng4f489172009-09-27 17:08:35 -0700813 ArmLIR *branch = opCondBranch(cUnit, cond);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700814 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
815 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700816}
817
Ben Chenge9695e52009-06-16 16:11:47 -0700818/*
819 * Perform null-check on a register. vReg is the Dalvik register being checked,
820 * and mReg is the machine register holding the actual value. If internal state
821 * indicates that vReg has been checked before the check request is ignored.
822 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700823static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
824 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700825{
Ben Chenge9695e52009-06-16 16:11:47 -0700826 /* This particular Dalvik register has been null-checked */
827 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
828 return pcrLabel;
829 }
830 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
831 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
832}
833
834/*
835 * Perform zero-check on a register. Similar to genNullCheck but the value being
836 * checked does not have a corresponding Dalvik register.
837 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700838static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
839 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -0700840{
841 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700842}
843
844/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700845static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
846 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847{
Ben Cheng0fd31e42009-09-03 14:40:16 -0700848 return genRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700849 pcrLabel);
850}
851
852/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700853static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
854 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700855{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700856 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700857 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
858}
859
860/* Load a wide field from an object instance */
861static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
862{
863 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700864 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700865
Ben Chenge9695e52009-06-16 16:11:47 -0700866 /* Allocate reg0..reg3 into physical registers r0..r3 */
867
868 /* See if vB is in a native register. If so, reuse it. */
869 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
870 /* Ping reg3 to the other register of the same pair containing reg2 */
871 reg3 = reg2 ^ 0x1;
872 /*
873 * Ping reg0 to the first register of the alternate register pair
874 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700875 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700876 reg1 = NEXT_REG(reg0);
877
878 loadValue(cUnit, dInsn->vB, reg2);
879 loadConstant(cUnit, reg3, fieldOffset);
880 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700881 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700882#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700883 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700884#else
885 int regMap = reg1 << 8 | reg0 << 4 | reg2;
886 selfVerificationMemOpWrapper(cUnit, regMap,
887 &selfVerificationLoadDoubleword);
Jeff Hao97319a82009-08-12 16:57:15 -0700888#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700889 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700890}
891
892/* Store a wide field to an object instance */
893static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
894{
895 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700896 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700897
Ben Chenge9695e52009-06-16 16:11:47 -0700898 /* Allocate reg0..reg3 into physical registers r0..r3 */
899
900 /* See if vB is in a native register. If so, reuse it. */
901 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
902 /* Ping reg3 to the other register of the same pair containing reg2 */
903 reg3 = reg2 ^ 0x1;
904 /*
905 * Ping reg0 to the first register of the alternate register pair
906 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700907 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700908 reg1 = NEXT_REG(reg0);
909
910
911 loadValue(cUnit, dInsn->vB, reg2);
912 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
913 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
914 loadConstant(cUnit, reg3, fieldOffset);
915 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700916 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700917#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700918 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700919#else
920 int regMap = reg1 << 8 | reg0 << 4 | reg2;
921 selfVerificationMemOpWrapper(cUnit, regMap,
922 &selfVerificationStoreDoubleword);
923#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700924}
925
926/*
927 * Load a field from an object instance
928 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700929 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700930static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700931 int fieldOffset)
932{
933 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700934 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700935
Ben Chenge9695e52009-06-16 16:11:47 -0700936 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
937 reg1 = NEXT_REG(reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700938 loadValue(cUnit, dInsn->vB, reg0);
Jeff Hao97319a82009-08-12 16:57:15 -0700939#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700940 loadBaseDisp(cUnit, mir, reg0, fieldOffset, reg1, size, true, dInsn->vB);
Jeff Hao97319a82009-08-12 16:57:15 -0700941#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700942 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700943 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700944 loadConstant(cUnit, reg1, fieldOffset);
945 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700946
Bill Buzbee270c1d62009-08-13 16:58:07 -0700947 int regMap = reg1 << 4 | reg0;
Jeff Hao97319a82009-08-12 16:57:15 -0700948 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
Jeff Hao97319a82009-08-12 16:57:15 -0700949#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700950 storeValue(cUnit, reg1, dInsn->vA, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700951}
952
953/*
954 * Store a field to an object instance
955 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700956 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700957static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700958 int fieldOffset)
959{
960 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700961 int reg0, reg1, reg2;
962
963 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
964 reg1 = NEXT_REG(reg0);
965 reg2 = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700966
Ben Chenge9695e52009-06-16 16:11:47 -0700967 loadValue(cUnit, dInsn->vB, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700968 loadValue(cUnit, dInsn->vA, reg2);
969 updateLiveRegister(cUnit, dInsn->vA, reg2);
970 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700971#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700972 storeBaseDisp(cUnit, reg0, fieldOffset, reg2, size, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700973#else
974 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700975 loadConstant(cUnit, reg1, fieldOffset);
976 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700977
978 int regMap = reg2 << 4 | reg0;
979 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
980
Bill Buzbee270c1d62009-08-13 16:58:07 -0700981 opRegReg(cUnit, OP_SUB, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700982#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700983}
984
985
Ben Chengba4fc8b2009-06-01 13:00:29 -0700986/*
987 * Generate array load
988 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700989 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700990static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700991 int vArray, int vIndex, int vDest, int scale)
992{
993 int lenOffset = offsetof(ArrayObject, length);
994 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700995 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700996
Ben Cheng9cac6da2009-09-27 11:07:01 -0700997 reg0 = selectFirstRegister(cUnit, vArray,
998 (size == LONG) || (size == DOUBLE));
Ben Chenge9695e52009-06-16 16:11:47 -0700999 reg1 = NEXT_REG(reg0);
1000 reg2 = NEXT_REG(reg1);
1001 reg3 = NEXT_REG(reg2);
1002
1003 loadValue(cUnit, vArray, reg2);
1004 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001005
1006 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001007 ArmLIR * pcrLabel = NULL;
1008
1009 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
1010 pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
1011 }
1012
1013 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1014 /* Get len */
1015 loadWordDisp(cUnit, reg2, lenOffset, reg0);
1016 /* reg2 -> array data */
1017 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1018 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
1019 } else {
1020 /* reg2 -> array data */
1021 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1022 }
Jeff Hao97319a82009-08-12 16:57:15 -07001023#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001024 if ((size == LONG) || (size == DOUBLE)) {
1025 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
1026 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1027 loadBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
1028 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
1029 loadBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
Ben Chenge9695e52009-06-16 16:11:47 -07001030 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001031 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001032 loadBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
Ben Chenge9695e52009-06-16 16:11:47 -07001033 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001034 }
Jeff Hao97319a82009-08-12 16:57:15 -07001035#else
Bill Buzbee270c1d62009-08-13 16:58:07 -07001036 //TODO: probably want to move this into loadBaseIndexed
1037 void *funct = NULL;
1038 switch(size) {
1039 case LONG:
1040 case DOUBLE:
Jeff Hao97319a82009-08-12 16:57:15 -07001041 funct = (void*) &selfVerificationLoadDoubleword;
1042 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001043 case WORD:
Jeff Hao97319a82009-08-12 16:57:15 -07001044 funct = (void*) &selfVerificationLoad;
1045 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001046 case UNSIGNED_HALF:
1047 funct = (void*) &selfVerificationLoadHalfword;
1048 break;
1049 case SIGNED_HALF:
1050 funct = (void*) &selfVerificationLoadSignedHalfword;
1051 break;
1052 case UNSIGNED_BYTE:
1053 funct = (void*) &selfVerificationLoadByte;
1054 break;
1055 case SIGNED_BYTE:
1056 funct = (void*) &selfVerificationLoadSignedByte;
1057 break;
1058 default:
1059 assert(0);
1060 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -07001061 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001062 /* Combine address and index */
1063 if (scale)
1064 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1065 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001066
1067 int regMap = reg1 << 8 | reg0 << 4 | reg2;
1068 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1069
Bill Buzbee270c1d62009-08-13 16:58:07 -07001070 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001071
Bill Buzbee270c1d62009-08-13 16:58:07 -07001072 if ((size == LONG) || (size == DOUBLE))
Jeff Hao97319a82009-08-12 16:57:15 -07001073 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
1074 else
1075 storeValue(cUnit, reg0, vDest, reg3);
1076#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001077}
1078
Ben Chengba4fc8b2009-06-01 13:00:29 -07001079/*
1080 * Generate array store
1081 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001082 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001083static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001084 int vArray, int vIndex, int vSrc, int scale)
1085{
1086 int lenOffset = offsetof(ArrayObject, length);
1087 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -07001088 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001089
Ben Cheng9cac6da2009-09-27 11:07:01 -07001090 reg0 = selectFirstRegister(cUnit, vArray,
1091 (size == LONG) || (size == DOUBLE));
Ben Chenge9695e52009-06-16 16:11:47 -07001092 reg1 = NEXT_REG(reg0);
1093 reg2 = NEXT_REG(reg1);
1094 reg3 = NEXT_REG(reg2);
1095
1096 loadValue(cUnit, vArray, reg2);
1097 loadValue(cUnit, vIndex, reg3);
1098
Ben Cheng1efc9c52009-06-08 18:25:27 -07001099 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001100 ArmLIR * pcrLabel = NULL;
1101
1102 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
1103 pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
1104 }
1105
1106 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1107 /* Get len */
1108 loadWordDisp(cUnit, reg2, lenOffset, reg0);
1109 /* reg2 -> array data */
1110 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1111 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
1112 } else {
1113 /* reg2 -> array data */
1114 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1115 }
1116
Ben Chenge9695e52009-06-16 16:11:47 -07001117 /* at this point, reg2 points to array, reg3 is unscaled index */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001118#if !defined(WITH_SELF_VERIFICATION)
1119 if ((size == LONG) || (size == DOUBLE)) {
1120 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
1121 loadValuePair(cUnit, vSrc, reg0, reg1);
1122 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
1123 if (scale)
1124 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1125 storeBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
1126 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
1127 storeBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
1128 } else {
1129 loadValue(cUnit, vSrc, reg0);
1130 updateLiveRegister(cUnit, vSrc, reg0);
1131 storeBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
1132 }
1133#else
1134 //TODO: probably want to move this into storeBaseIndexed
1135 void *funct = NULL;
1136 switch(size) {
1137 case LONG:
1138 case DOUBLE:
1139 funct = (void*) &selfVerificationStoreDoubleword;
1140 break;
1141 case WORD:
1142 funct = (void*) &selfVerificationStore;
1143 break;
1144 case SIGNED_HALF:
1145 case UNSIGNED_HALF:
1146 funct = (void*) &selfVerificationStoreHalfword;
1147 break;
1148 case SIGNED_BYTE:
1149 case UNSIGNED_BYTE:
1150 funct = (void*) &selfVerificationStoreByte;
1151 break;
1152 default:
1153 assert(0);
1154 dvmAbort();
1155 }
1156
1157 /* Combine address and index */
1158 if ((size == LONG) || (size == DOUBLE)) {
Ben Chenge9695e52009-06-16 16:11:47 -07001159 loadValuePair(cUnit, vSrc, reg0, reg1);
1160 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001161 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001162 loadValue(cUnit, vSrc, reg0);
1163 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001164 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001165 if (scale)
1166 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1167 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001168
1169 int regMap = reg1 << 8 | reg0 << 4 | reg2;
1170 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1171
Bill Buzbee270c1d62009-08-13 16:58:07 -07001172 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001173#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001174}
1175
1176static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1177 int vSrc1, int vShift)
1178{
Ben Chenge9695e52009-06-16 16:11:47 -07001179 /*
1180 * Don't mess with the regsiters here as there is a particular calling
1181 * convention to the out-of-line handler.
1182 */
1183 loadValue(cUnit, vShift, r2);
1184 loadValuePair(cUnit, vSrc1, r0, r1);
1185 switch( mir->dalvikInsn.opCode) {
1186 case OP_SHL_LONG:
1187 case OP_SHL_LONG_2ADDR:
1188 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1189 break;
1190 case OP_SHR_LONG:
1191 case OP_SHR_LONG_2ADDR:
1192 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1193 break;
1194 case OP_USHR_LONG:
1195 case OP_USHR_LONG_2ADDR:
1196 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1197 break;
1198 default:
1199 return true;
1200 }
1201 storeValuePair(cUnit, r0, r1, vDest, r2);
1202 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001203}
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001204bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1205 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001206{
Ben Chenge9695e52009-06-16 16:11:47 -07001207 /*
1208 * Don't optimize the regsiter usage here as they are governed by the EABI
1209 * calling convention.
1210 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001211 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001212 int reg0, reg1;
1213
Ben Chengba4fc8b2009-06-01 13:00:29 -07001214 /* TODO: use a proper include file to define these */
1215 float __aeabi_fadd(float a, float b);
1216 float __aeabi_fsub(float a, float b);
1217 float __aeabi_fdiv(float a, float b);
1218 float __aeabi_fmul(float a, float b);
1219 float fmodf(float a, float b);
1220
Ben Chenge9695e52009-06-16 16:11:47 -07001221 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1222 reg1 = NEXT_REG(reg0);
1223
Ben Chengba4fc8b2009-06-01 13:00:29 -07001224 switch (mir->dalvikInsn.opCode) {
1225 case OP_ADD_FLOAT_2ADDR:
1226 case OP_ADD_FLOAT:
1227 funct = (void*) __aeabi_fadd;
1228 break;
1229 case OP_SUB_FLOAT_2ADDR:
1230 case OP_SUB_FLOAT:
1231 funct = (void*) __aeabi_fsub;
1232 break;
1233 case OP_DIV_FLOAT_2ADDR:
1234 case OP_DIV_FLOAT:
1235 funct = (void*) __aeabi_fdiv;
1236 break;
1237 case OP_MUL_FLOAT_2ADDR:
1238 case OP_MUL_FLOAT:
1239 funct = (void*) __aeabi_fmul;
1240 break;
1241 case OP_REM_FLOAT_2ADDR:
1242 case OP_REM_FLOAT:
1243 funct = (void*) fmodf;
1244 break;
1245 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -07001246 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001247 opRegImm(cUnit, OP_ADD, reg0, 0x80000000, reg1);
Ben Chenge9695e52009-06-16 16:11:47 -07001248 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001249 return false;
1250 }
1251 default:
1252 return true;
1253 }
1254 loadConstant(cUnit, r2, (int)funct);
1255 loadValue(cUnit, vSrc1, r0);
1256 loadValue(cUnit, vSrc2, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001257 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001258 storeValue(cUnit, r0, vDest, r1);
1259 return false;
1260}
1261
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001262bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1263 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001264{
1265 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001266 int reg0, reg1, reg2;
1267
Ben Chengba4fc8b2009-06-01 13:00:29 -07001268 /* TODO: use a proper include file to define these */
1269 double __aeabi_dadd(double a, double b);
1270 double __aeabi_dsub(double a, double b);
1271 double __aeabi_ddiv(double a, double b);
1272 double __aeabi_dmul(double a, double b);
1273 double fmod(double a, double b);
1274
Ben Chenge9695e52009-06-16 16:11:47 -07001275 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1276 reg1 = NEXT_REG(reg0);
1277 reg2 = NEXT_REG(reg1);
1278
Ben Chengba4fc8b2009-06-01 13:00:29 -07001279 switch (mir->dalvikInsn.opCode) {
1280 case OP_ADD_DOUBLE_2ADDR:
1281 case OP_ADD_DOUBLE:
1282 funct = (void*) __aeabi_dadd;
1283 break;
1284 case OP_SUB_DOUBLE_2ADDR:
1285 case OP_SUB_DOUBLE:
1286 funct = (void*) __aeabi_dsub;
1287 break;
1288 case OP_DIV_DOUBLE_2ADDR:
1289 case OP_DIV_DOUBLE:
1290 funct = (void*) __aeabi_ddiv;
1291 break;
1292 case OP_MUL_DOUBLE_2ADDR:
1293 case OP_MUL_DOUBLE:
1294 funct = (void*) __aeabi_dmul;
1295 break;
1296 case OP_REM_DOUBLE_2ADDR:
1297 case OP_REM_DOUBLE:
1298 funct = (void*) fmod;
1299 break;
1300 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001301 loadValuePair(cUnit, vSrc2, reg0, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001302 opRegImm(cUnit, OP_ADD, reg1, 0x80000000, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001303 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001304 return false;
1305 }
1306 default:
1307 return true;
1308 }
Ben Chenge9695e52009-06-16 16:11:47 -07001309 /*
1310 * Don't optimize the regsiter usage here as they are governed by the EABI
1311 * calling convention.
1312 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001313 loadConstant(cUnit, r4PC, (int)funct);
1314 loadValuePair(cUnit, vSrc1, r0, r1);
1315 loadValuePair(cUnit, vSrc2, r2, r3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001316 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001317 storeValuePair(cUnit, r0, r1, vDest, r2);
1318 return false;
1319}
1320
1321static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1322 int vSrc1, int vSrc2)
1323{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001324 OpKind firstOp = OP_BKPT;
1325 OpKind secondOp = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001326 bool callOut = false;
1327 void *callTgt;
1328 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -07001329 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001330 /* TODO - find proper .h file to declare these */
1331 long long __aeabi_ldivmod(long long op1, long long op2);
1332
1333 switch (mir->dalvikInsn.opCode) {
1334 case OP_NOT_LONG:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001335 firstOp = OP_MVN;
1336 secondOp = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001337 break;
1338 case OP_ADD_LONG:
1339 case OP_ADD_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001340 firstOp = OP_ADD;
1341 secondOp = OP_ADC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001342 break;
1343 case OP_SUB_LONG:
1344 case OP_SUB_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001345 firstOp = OP_SUB;
1346 secondOp = OP_SBC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001347 break;
1348 case OP_MUL_LONG:
1349 case OP_MUL_LONG_2ADDR:
1350 loadValuePair(cUnit, vSrc1, r0, r1);
1351 loadValuePair(cUnit, vSrc2, r2, r3);
1352 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
1353 storeValuePair(cUnit, r0, r1, vDest, r2);
1354 return false;
1355 break;
1356 case OP_DIV_LONG:
1357 case OP_DIV_LONG_2ADDR:
1358 callOut = true;
1359 retReg = r0;
1360 callTgt = (void*)__aeabi_ldivmod;
1361 break;
1362 /* NOTE - result is in r2/r3 instead of r0/r1 */
1363 case OP_REM_LONG:
1364 case OP_REM_LONG_2ADDR:
1365 callOut = true;
1366 callTgt = (void*)__aeabi_ldivmod;
1367 retReg = r2;
1368 break;
1369 case OP_AND_LONG:
1370 case OP_AND_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001371 firstOp = OP_AND;
1372 secondOp = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001373 break;
1374 case OP_OR_LONG:
1375 case OP_OR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001376 firstOp = OP_OR;
1377 secondOp = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001378 break;
1379 case OP_XOR_LONG:
1380 case OP_XOR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001381 firstOp = OP_XOR;
1382 secondOp = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001383 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001384 case OP_NEG_LONG: {
1385 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1386 reg1 = NEXT_REG(reg0);
1387 reg2 = NEXT_REG(reg1);
1388 reg3 = NEXT_REG(reg2);
1389
1390 loadValuePair(cUnit, vSrc2, reg0, reg1);
1391 loadConstant(cUnit, reg3, 0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001392 opRegRegReg(cUnit, OP_SUB, reg2, reg3, reg0);
1393 opRegReg(cUnit, OP_SBC, reg3, reg1);
Ben Cheng38329f52009-07-07 14:19:20 -07001394 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001395 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001396 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001397 default:
1398 LOGE("Invalid long arith op");
1399 dvmAbort();
1400 }
1401 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001402 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1403 reg1 = NEXT_REG(reg0);
1404 reg2 = NEXT_REG(reg1);
1405 reg3 = NEXT_REG(reg2);
1406
1407 loadValuePair(cUnit, vSrc1, reg0, reg1);
1408 loadValuePair(cUnit, vSrc2, reg2, reg3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001409 opRegReg(cUnit, firstOp, reg0, reg2);
1410 opRegReg(cUnit, secondOp, reg1, reg3);
1411 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001412 /*
Bill Buzbee270c1d62009-08-13 16:58:07 -07001413 * Don't optimize the register usage here as they are governed by the EABI
Ben Chenge9695e52009-06-16 16:11:47 -07001414 * calling convention.
1415 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001416 } else {
1417 loadValuePair(cUnit, vSrc2, r2, r3);
1418 loadConstant(cUnit, r4PC, (int) callTgt);
1419 loadValuePair(cUnit, vSrc1, r0, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001420 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001421 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1422 }
1423 return false;
1424}
1425
1426static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1427 int vSrc1, int vSrc2)
1428{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001429 OpKind op = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001430 bool callOut = false;
1431 bool checkZero = false;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001432 bool threeOperand = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001433 int retReg = r0;
1434 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -07001435 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001436
1437 /* TODO - find proper .h file to declare these */
1438 int __aeabi_idivmod(int op1, int op2);
1439 int __aeabi_idiv(int op1, int op2);
1440
1441 switch (mir->dalvikInsn.opCode) {
1442 case OP_NEG_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001443 op = OP_NEG;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001444 break;
1445 case OP_NOT_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001446 op = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001447 break;
1448 case OP_ADD_INT:
1449 case OP_ADD_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001450 op = OP_ADD;
1451 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001452 break;
1453 case OP_SUB_INT:
1454 case OP_SUB_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001455 op = OP_SUB;
1456 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001457 break;
1458 case OP_MUL_INT:
1459 case OP_MUL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001460 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001461 break;
1462 case OP_DIV_INT:
1463 case OP_DIV_INT_2ADDR:
1464 callOut = true;
1465 checkZero = true;
1466 callTgt = __aeabi_idiv;
1467 retReg = r0;
1468 break;
1469 /* NOTE: returns in r1 */
1470 case OP_REM_INT:
1471 case OP_REM_INT_2ADDR:
1472 callOut = true;
1473 checkZero = true;
1474 callTgt = __aeabi_idivmod;
1475 retReg = r1;
1476 break;
1477 case OP_AND_INT:
1478 case OP_AND_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001479 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001480 break;
1481 case OP_OR_INT:
1482 case OP_OR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001483 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001484 break;
1485 case OP_XOR_INT:
1486 case OP_XOR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001487 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001488 break;
1489 case OP_SHL_INT:
1490 case OP_SHL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001491 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001492 break;
1493 case OP_SHR_INT:
1494 case OP_SHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001495 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001496 break;
1497 case OP_USHR_INT:
1498 case OP_USHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001499 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001500 break;
1501 default:
1502 LOGE("Invalid word arith op: 0x%x(%d)",
1503 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1504 dvmAbort();
1505 }
1506 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001507 /* Try to allocate reg0 to the currently cached source operand */
1508 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1509 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1510 reg1 = NEXT_REG(reg0);
1511 regDest = NEXT_REG(reg1);
1512
1513 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1514 loadValue(cUnit, vSrc2, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001515 if (threeOperand) {
1516 opRegRegReg(cUnit, op, regDest, reg0, reg1);
1517 storeValue(cUnit, regDest, vDest, reg1);
1518 } else {
1519 opRegReg(cUnit, op, reg0, reg1);
1520 storeValue(cUnit, reg0, vDest, reg1);
1521 }
Ben Chenge9695e52009-06-16 16:11:47 -07001522 } else {
1523 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1524 reg1 = NEXT_REG(reg0);
1525 regDest = NEXT_REG(reg1);
1526
1527 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1528 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001529 if (threeOperand) {
1530 opRegRegReg(cUnit, op, regDest, reg1, reg0);
1531 storeValue(cUnit, regDest, vDest, reg1);
1532 } else {
1533 opRegReg(cUnit, op, reg1, reg0);
1534 storeValue(cUnit, reg1, vDest, reg0);
1535 }
Ben Chenge9695e52009-06-16 16:11:47 -07001536 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001537 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001538 /*
1539 * Load the callout target first since it will never be eliminated
1540 * and its value will be used first.
1541 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001542 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -07001543 /*
1544 * Load vSrc2 first if it is not cached in a native register or it
1545 * is in r0 which will be clobbered if vSrc1 is loaded first.
1546 */
1547 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1548 cUnit->registerScoreboard.nativeReg == r0) {
1549 /* Cannot be optimized and won't clobber r0 */
1550 loadValue(cUnit, vSrc2, r1);
1551 /* May be optimized if vSrc1 is cached */
1552 loadValue(cUnit, vSrc1, r0);
1553 } else {
1554 loadValue(cUnit, vSrc1, r0);
1555 loadValue(cUnit, vSrc2, r1);
1556 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001557 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -07001558 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001559 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001560 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001561 storeValue(cUnit, retReg, vDest, r2);
1562 }
1563 return false;
1564}
1565
1566static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1567{
1568 OpCode opCode = mir->dalvikInsn.opCode;
1569 int vA = mir->dalvikInsn.vA;
1570 int vB = mir->dalvikInsn.vB;
1571 int vC = mir->dalvikInsn.vC;
1572
1573 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1574 return genArithOpLong(cUnit,mir, vA, vA, vB);
1575 }
1576 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1577 return genArithOpLong(cUnit,mir, vA, vB, vC);
1578 }
1579 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1580 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1581 }
1582 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1583 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1584 }
1585 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1586 return genArithOpInt(cUnit,mir, vA, vA, vB);
1587 }
1588 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1589 return genArithOpInt(cUnit,mir, vA, vB, vC);
1590 }
1591 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001592 return genArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001593 }
1594 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001595 return genArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001596 }
1597 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001598 return genArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001599 }
1600 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001601 return genArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001602 }
1603 return true;
1604}
1605
Bill Buzbeed45ba372009-06-15 17:00:57 -07001606static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1607 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001608{
Ben Chenge9695e52009-06-16 16:11:47 -07001609 /*
1610 * Don't optimize the register usage since it calls out to template
1611 * functions
1612 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001613 loadConstant(cUnit, r2, (int)funct);
1614 if (srcSize == 1) {
1615 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1616 } else {
1617 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1618 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001619 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001620 if (tgtSize == 1) {
1621 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1622 } else {
1623 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1624 }
1625 return false;
1626}
1627
Ben Chengba4fc8b2009-06-01 13:00:29 -07001628static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1629 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001630 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001631{
1632 unsigned int i;
1633 unsigned int regMask = 0;
1634
1635 /* Load arguments to r0..r4 */
1636 for (i = 0; i < dInsn->vA; i++) {
1637 regMask |= 1 << i;
1638 loadValue(cUnit, dInsn->arg[i], i);
1639 }
1640 if (regMask) {
1641 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001642 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1643 sizeof(StackSaveArea) + (dInsn->vA << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001644 /* generate null check */
1645 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001646 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1647 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001648 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001649 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001650 }
1651}
1652
1653static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1654 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001655 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001656{
1657 int srcOffset = dInsn->vC << 2;
1658 int numArgs = dInsn->vA;
1659 int regMask;
1660 /*
1661 * r4PC : &rFP[vC]
1662 * r7: &newFP[0]
1663 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001664 opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001665 /* load [r0 .. min(numArgs,4)] */
1666 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001667 /*
1668 * Protect the loadMultiple instruction from being reordered with other
1669 * Dalvik stack accesses.
1670 */
1671 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001672 loadMultiple(cUnit, r4PC, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001673 genBarrier(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001674
Bill Buzbee270c1d62009-08-13 16:58:07 -07001675 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1676 sizeof(StackSaveArea) + (numArgs << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001677 /* generate null check */
1678 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001679 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001680 }
1681
1682 /*
1683 * Handle remaining 4n arguments:
1684 * store previously loaded 4 values and load the next 4 values
1685 */
1686 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001687 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001688 /*
1689 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001690 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001691 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001692 opImm(cUnit, OP_PUSH, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001693 /* No need to generate the loop structure if numArgs <= 11 */
1694 if (numArgs > 11) {
1695 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001696 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengd7d426a2009-09-22 11:23:36 -07001697 loopLabel->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001698 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001699 storeMultiple(cUnit, r7, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001700 /*
1701 * Protect the loadMultiple instruction from being reordered with other
1702 * Dalvik stack accesses.
1703 */
1704 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001705 loadMultiple(cUnit, r4PC, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001706 genBarrier(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001707 /* No need to generate the loop structure if numArgs <= 11 */
1708 if (numArgs > 11) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001709 opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001710 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1711 }
1712 }
1713
1714 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001715 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001716
1717 /* Generate the loop epilogue - don't use r0 */
1718 if ((numArgs > 4) && (numArgs % 4)) {
1719 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001720 /*
1721 * Protect the loadMultiple instruction from being reordered with other
1722 * Dalvik stack accesses.
1723 */
1724 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001725 loadMultiple(cUnit, r4PC, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001726 genBarrier(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001727 }
1728 if (numArgs >= 8)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001729 opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001730
1731 /* Save the modulo 4 arguments */
1732 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001733 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001734 }
1735}
1736
Ben Cheng38329f52009-07-07 14:19:20 -07001737/*
1738 * Generate code to setup the call stack then jump to the chaining cell if it
1739 * is not a native method.
1740 */
1741static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001742 BasicBlock *bb, ArmLIR *labelList,
1743 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001744 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001745{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001746 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001747
1748 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001749 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001750 /* r4PC = dalvikCallsite */
1751 loadConstant(cUnit, r4PC,
1752 (int) (cUnit->method->insns + mir->offset));
1753 addrRetChain->generic.target = (LIR *) retChainingCell;
1754 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001755 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001756 * r1 = &ChainingCell
1757 * r4PC = callsiteDPC
1758 */
1759 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001760 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001761#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001762 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001763#endif
1764 } else {
1765 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1766#if defined(INVOKE_STATS)
1767 gDvmJit.invokeChain++;
1768#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001769 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001770 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1771 }
1772 /* Handle exceptions using the interpreter */
1773 genTrap(cUnit, mir->offset, pcrLabel);
1774}
1775
Ben Cheng38329f52009-07-07 14:19:20 -07001776/*
1777 * Generate code to check the validity of a predicted chain and take actions
1778 * based on the result.
1779 *
1780 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1781 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1782 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1783 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1784 * 0x426a99b2 : blx_2 see above --+
1785 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1786 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1787 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1788 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1789 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1790 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1791 * 0x426a99c0 : blx r7 --+
1792 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1793 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1794 * 0x426a99c6 : blx_2 see above --+
1795 */
1796static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1797 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001798 ArmLIR *retChainingCell,
1799 ArmLIR *predChainingCell,
1800 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001801{
1802 /* "this" is already left in r0 by genProcessArgs* */
1803
1804 /* r4PC = dalvikCallsite */
1805 loadConstant(cUnit, r4PC,
1806 (int) (cUnit->method->insns + mir->offset));
1807
1808 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001809 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001810 addrRetChain->generic.target = (LIR *) retChainingCell;
1811
1812 /* r2 = &predictedChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001813 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, OP_ADD, r2, rpc, 0,
1814 rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001815 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1816
1817 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1818
1819 /* return through lr - jump to the chaining cell */
1820 genUnconditionalBranch(cUnit, predChainingCell);
1821
1822 /*
1823 * null-check on "this" may have been eliminated, but we still need a PC-
1824 * reconstruction label for stack overflow bailout.
1825 */
1826 if (pcrLabel == NULL) {
1827 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001828 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1829 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001830 pcrLabel->operands[0] = dPC;
1831 pcrLabel->operands[1] = mir->offset;
1832 /* Insert the place holder to the growable list */
1833 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1834 }
1835
1836 /* return through lr+2 - punt to the interpreter */
1837 genUnconditionalBranch(cUnit, pcrLabel);
1838
1839 /*
1840 * return through lr+4 - fully resolve the callee method.
1841 * r1 <- count
1842 * r2 <- &predictedChainCell
1843 * r3 <- this->class
1844 * r4 <- dPC
1845 * r7 <- this->class->vtable
1846 */
1847
1848 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001849 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001850
1851 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001852 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001853
Ben Cheng4f489172009-09-27 17:08:35 -07001854 ArmLIR *bypassRechaining = opCondBranch(cUnit, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001855
Bill Buzbee270c1d62009-08-13 16:58:07 -07001856 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1857 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001858
1859 /*
1860 * r0 = calleeMethod
1861 * r2 = &predictedChainingCell
1862 * r3 = class
1863 *
1864 * &returnChainingCell has been loaded into r1 but is not needed
1865 * when patching the chaining cell and will be clobbered upon
1866 * returning so it will be reconstructed again.
1867 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001868 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001869
1870 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001871 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001872 addrRetChain->generic.target = (LIR *) retChainingCell;
1873
1874 bypassRechaining->generic.target = (LIR *) addrRetChain;
1875 /*
1876 * r0 = calleeMethod,
1877 * r1 = &ChainingCell,
1878 * r4PC = callsiteDPC,
1879 */
1880 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1881#if defined(INVOKE_STATS)
1882 gDvmJit.invokePredictedChain++;
1883#endif
1884 /* Handle exceptions using the interpreter */
1885 genTrap(cUnit, mir->offset, pcrLabel);
1886}
1887
1888/*
1889 * Up calling this function, "this" is stored in r0. The actual class will be
1890 * chased down off r0 and the predicted one will be retrieved through
1891 * predictedChainingCell then a comparison is performed to see whether the
1892 * previously established chaining is still valid.
1893 *
1894 * The return LIR is a branch based on the comparison result. The actual branch
1895 * target will be setup in the caller.
1896 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001897static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1898 ArmLIR *predChainingCell,
1899 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001900 MIR *mir)
1901{
1902 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001903 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001904
1905 /*
1906 * r2 now contains predicted class. The starting offset of the
1907 * cached value is 4 bytes into the chaining cell.
1908 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001909 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001910 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07001911 getPredictedClass->generic.target = (LIR *) predChainingCell;
1912
1913 /*
1914 * r0 now contains predicted method. The starting offset of the
1915 * cached value is 8 bytes into the chaining cell.
1916 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001917 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001918 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001919 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1920
1921 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001922 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001923 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001924 getRechainingRequestCount->generic.target =
1925 (LIR *) predChainingCell;
1926
1927 /* r4PC = dalvikCallsite */
1928 loadConstant(cUnit, r4PC,
1929 (int) (cUnit->method->insns + mir->offset));
1930
1931 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001932 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001933 addrRetChain->generic.target = (LIR *) retChainingCell;
1934
1935 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001936 opRegReg(cUnit, OP_CMP, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001937
Ben Cheng4f489172009-09-27 17:08:35 -07001938 return opCondBranch(cUnit, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001939}
1940
Ben Chengba4fc8b2009-06-01 13:00:29 -07001941/* Geneate a branch to go back to the interpreter */
1942static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1943{
1944 /* r0 = dalvik pc */
1945 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001946 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1947 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1948 jitToInterpEntries.dvmJitToInterpPunt), r1);
1949 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001950}
1951
1952/*
1953 * Attempt to single step one instruction using the interpreter and return
1954 * to the compiled code for the next Dalvik instruction
1955 */
1956static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1957{
1958 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1959 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1960 kInstrCanThrow;
1961 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1962 genPuntToInterp(cUnit, mir->offset);
1963 return;
1964 }
1965 int entryAddr = offsetof(InterpState,
1966 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001967 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001968 /* r0 = dalvik pc */
1969 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1970 /* r1 = dalvik pc of following instruction */
1971 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001972 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001973}
1974
Bill Buzbee270c1d62009-08-13 16:58:07 -07001975/* Generate conditional branch instructions */
1976static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1977 ArmConditionCode cond,
1978 ArmLIR *target)
1979{
Ben Cheng4f489172009-09-27 17:08:35 -07001980 ArmLIR *branch = opCondBranch(cUnit, cond);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001981 branch->generic.target = (LIR *) target;
1982 return branch;
1983}
Ben Chengba4fc8b2009-06-01 13:00:29 -07001984
Bill Buzbee270c1d62009-08-13 16:58:07 -07001985/* Generate unconditional branch instructions */
1986static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1987{
1988 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
1989 branch->generic.target = (LIR *) target;
1990 return branch;
1991}
1992
1993/* Load the address of a Dalvik register on the frame */
1994static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
1995{
1996 return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
1997}
1998
1999/* Load a single value from rFP[src] and store them into rDest */
2000static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
2001{
2002 return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
2003}
2004
2005/* Load a word at base + displacement. Displacement must be word multiple */
2006static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
2007 int rDest)
2008{
2009 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
2010 -1);
2011}
2012
2013static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
2014 int displacement, int rSrc, int rScratch)
2015{
2016 return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
2017}
2018
2019/* Store a value from rSrc to vDest */
2020static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
2021 int rScratch)
2022{
2023 killNullCheckedRegister(cUnit, vDest);
2024 updateLiveRegister(cUnit, vDest, rSrc);
2025 return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
2026}
2027/*
2028 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
2029 * rDestHi
2030 */
2031static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
2032 int rDestHi)
2033{
2034 ArmLIR *res;
2035 /* Use reg + imm5*4 to load the values if possible */
2036 if (vSrc <= 30) {
2037 res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
2038 loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
2039 } else {
2040 assert(rDestLo < rDestHi);
2041 res = loadValueAddress(cUnit, vSrc, rDestLo);
Ben Chengd7d426a2009-09-22 11:23:36 -07002042 /*
2043 * Protect the loadMultiple instruction from being reordered with other
2044 * Dalvik stack accesses.
2045 */
2046 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002047 loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
Ben Chengd7d426a2009-09-22 11:23:36 -07002048 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002049 }
2050 return res;
2051}
2052
2053/*
2054 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
2055 * vDest+1
2056 */
2057static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
2058 int vDest, int rScratch)
2059{
2060 ArmLIR *res;
2061 killNullCheckedRegister(cUnit, vDest);
2062 killNullCheckedRegister(cUnit, vDest+1);
2063 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
2064
2065 /* Use reg + imm5*4 to store the values if possible */
2066 if (vDest <= 30) {
2067 res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
2068 storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
2069 } else {
2070 assert(rSrcLo < rSrcHi);
2071 res = loadValueAddress(cUnit, vDest, rScratch);
Ben Chengd7d426a2009-09-22 11:23:36 -07002072 /*
2073 * Protect the storeMultiple instruction from being reordered with
2074 * other Dalvik stack accesses.
2075 */
2076 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002077 storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
Ben Chengd7d426a2009-09-22 11:23:36 -07002078 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002079 }
2080 return res;
2081}
2082
2083static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
2084{
2085 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
2086 dvmCompilerAppendLIR(cUnit, (LIR*)res);
2087 return res;
2088}
2089
Ben Chengba4fc8b2009-06-01 13:00:29 -07002090/*
2091 * The following are the first-level codegen routines that analyze the format
2092 * of each bytecode then either dispatch special purpose codegen routines
2093 * or produce corresponding Thumb instructions directly.
2094 */
2095
2096static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002097 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002098{
2099 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2100 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2101 return false;
2102}
2103
2104static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
2105{
2106 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2107 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
2108 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
2109 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2110 return true;
2111 }
2112 switch (dalvikOpCode) {
2113 case OP_RETURN_VOID:
2114 genReturnCommon(cUnit,mir);
2115 break;
2116 case OP_UNUSED_73:
2117 case OP_UNUSED_79:
2118 case OP_UNUSED_7A:
2119 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2120 return true;
2121 case OP_NOP:
2122 break;
2123 default:
2124 return true;
2125 }
2126 return false;
2127}
2128
2129static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2130{
Ben Chenge9695e52009-06-16 16:11:47 -07002131 int reg0, reg1, reg2;
2132
Ben Chengba4fc8b2009-06-01 13:00:29 -07002133 switch (mir->dalvikInsn.opCode) {
2134 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07002135 case OP_CONST_4: {
2136 /* Avoid using the previously used register */
2137 reg0 = selectFirstRegister(cUnit, vNone, false);
2138 reg1 = NEXT_REG(reg0);
2139 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
2140 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002141 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002142 }
2143 case OP_CONST_WIDE_32: {
2144 /* Avoid using the previously used register */
2145 reg0 = selectFirstRegister(cUnit, vNone, true);
2146 reg1 = NEXT_REG(reg0);
2147 reg2 = NEXT_REG(reg1);
2148 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002149 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002150 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002151 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002152 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002153 default:
2154 return true;
2155 }
2156 return false;
2157}
2158
2159static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2160{
Ben Chenge9695e52009-06-16 16:11:47 -07002161 int reg0, reg1, reg2;
2162
2163 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002164 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07002165 case OP_CONST_HIGH16: {
2166 reg0 = selectFirstRegister(cUnit, vNone, false);
2167 reg1 = NEXT_REG(reg0);
2168 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
2169 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002170 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002171 }
2172 case OP_CONST_WIDE_HIGH16: {
2173 reg0 = selectFirstRegister(cUnit, vNone, true);
2174 reg1 = NEXT_REG(reg0);
2175 reg2 = NEXT_REG(reg1);
2176 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
2177 loadConstant(cUnit, reg0, 0);
2178 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002179 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002180 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002181 default:
2182 return true;
2183 }
2184 return false;
2185}
2186
2187static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2188{
2189 /* For OP_THROW_VERIFICATION_ERROR */
2190 genInterpSingleStep(cUnit, mir);
2191 return false;
2192}
2193
2194static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2195{
Ben Chenge9695e52009-06-16 16:11:47 -07002196 /* Native register to use if the interested value is vA */
2197 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2198 /* Native register to use if source is not from Dalvik registers */
2199 int regvNone = selectFirstRegister(cUnit, vNone, false);
2200 /* Similar to regvA but for 64-bit values */
2201 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
2202 /* Similar to regvNone but for 64-bit values */
2203 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
2204
Ben Chengba4fc8b2009-06-01 13:00:29 -07002205 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002206 case OP_CONST_STRING_JUMBO:
2207 case OP_CONST_STRING: {
2208 void *strPtr = (void*)
2209 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2210 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002211 loadConstant(cUnit, regvNone, (int) strPtr );
2212 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002213 break;
2214 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002215 case OP_CONST_CLASS: {
2216 void *classPtr = (void*)
2217 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2218 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002219 loadConstant(cUnit, regvNone, (int) classPtr );
2220 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002221 break;
2222 }
2223 case OP_SGET_OBJECT:
2224 case OP_SGET_BOOLEAN:
2225 case OP_SGET_CHAR:
2226 case OP_SGET_BYTE:
2227 case OP_SGET_SHORT:
2228 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002229 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002230 void *fieldPtr = (void*)
2231 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2232 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002233 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002234#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002235 loadWordDisp(cUnit, regvNone, 0, regvNone);
Jeff Hao97319a82009-08-12 16:57:15 -07002236#else
2237 int regMap = regvNone << 4 | regvNone;
2238 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2239
Jeff Hao97319a82009-08-12 16:57:15 -07002240#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002241 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002242 break;
2243 }
2244 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002245 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002246 void *fieldPtr = (void*)
2247 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002248 int reg0, reg1, reg2;
2249
Ben Chengba4fc8b2009-06-01 13:00:29 -07002250 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002251 reg0 = regvNoneWide;
2252 reg1 = NEXT_REG(reg0);
2253 reg2 = NEXT_REG(reg1);
2254 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002255#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002256 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002257#else
2258 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2259 selfVerificationMemOpWrapper(cUnit, regMap,
2260 &selfVerificationLoadDoubleword);
2261
Jeff Hao97319a82009-08-12 16:57:15 -07002262#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002263 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002264 break;
2265 }
2266 case OP_SPUT_OBJECT:
2267 case OP_SPUT_BOOLEAN:
2268 case OP_SPUT_CHAR:
2269 case OP_SPUT_BYTE:
2270 case OP_SPUT_SHORT:
2271 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002272 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002273 void *fieldPtr = (void*)
2274 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002275
Ben Chengba4fc8b2009-06-01 13:00:29 -07002276 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002277 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
2278 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
2279 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002280#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002281 storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
Jeff Hao97319a82009-08-12 16:57:15 -07002282#else
2283 int regMap = regvA << 4 | NEXT_REG(regvA);
2284 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2285#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002286 break;
2287 }
2288 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002289 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002290 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002291 void *fieldPtr = (void*)
2292 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002293
Ben Chengba4fc8b2009-06-01 13:00:29 -07002294 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002295 reg0 = regvAWide;
2296 reg1 = NEXT_REG(reg0);
2297 reg2 = NEXT_REG(reg1);
2298 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2299 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2300 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002301#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002302 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002303#else
2304 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2305 selfVerificationMemOpWrapper(cUnit, regMap,
2306 &selfVerificationStoreDoubleword);
2307#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002308 break;
2309 }
2310 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002311 /*
2312 * Obey the calling convention and don't mess with the register
2313 * usage.
2314 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002315 ClassObject *classPtr = (void*)
2316 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2317 assert(classPtr != NULL);
2318 assert(classPtr->status & CLASS_INITIALIZED);
2319 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
2320 /* It's going to throw, just let the interp. deal with it. */
2321 genInterpSingleStep(cUnit, mir);
2322 return false;
2323 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002324 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002325 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002326 genExportPC(cUnit, mir, r2, r3 );
2327 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002328 opReg(cUnit, OP_BLX, r4PC);
Ben Cheng4f489172009-09-27 17:08:35 -07002329 /* generate a branch over if allocation is successful */
2330 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
2331 ArmLIR *branchOver = opCondBranch(cUnit, ARM_COND_NE);
2332 /*
2333 * OOM exception needs to be thrown here and cannot re-execute
2334 */
2335 loadConstant(cUnit, r0,
2336 (int) (cUnit->method->insns + mir->offset));
2337 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2338 /* noreturn */
2339
2340 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
2341 target->defMask = ENCODE_ALL;
2342 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002343 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2344 break;
2345 }
2346 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002347 /*
2348 * Obey the calling convention and don't mess with the register
2349 * usage.
2350 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002351 ClassObject *classPtr =
2352 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2353 loadConstant(cUnit, r1, (int) classPtr );
2354 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002355 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* Null? */
Ben Cheng4f489172009-09-27 17:08:35 -07002356 ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002357 /* r0 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002358 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002359 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002360 opRegReg(cUnit, OP_CMP, r0, r1);
Ben Cheng4f489172009-09-27 17:08:35 -07002361 ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_EQ);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002362 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002363 /* check cast failed - punt to the interpreter */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002364 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002365 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002366 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengd7d426a2009-09-22 11:23:36 -07002367 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002368 branch1->generic.target = (LIR *)target;
2369 branch2->generic.target = (LIR *)target;
2370 break;
2371 }
2372 default:
2373 return true;
2374 }
2375 return false;
2376}
2377
2378static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2379{
2380 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2381 switch (dalvikOpCode) {
2382 case OP_MOVE_EXCEPTION: {
2383 int offset = offsetof(InterpState, self);
2384 int exOffset = offsetof(Thread, exception);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002385 loadWordDisp(cUnit, rGLUE, offset, r1);
2386 loadWordDisp(cUnit, r1, exOffset, r0);
Ben Chenge9695e52009-06-16 16:11:47 -07002387 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002388 break;
2389 }
2390 case OP_MOVE_RESULT:
2391 case OP_MOVE_RESULT_OBJECT: {
2392 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002393 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002394 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2395 break;
2396 }
2397 case OP_MOVE_RESULT_WIDE: {
2398 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002399 loadWordDisp(cUnit, rGLUE, offset, r0);
2400 loadWordDisp(cUnit, rGLUE, offset+4, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002401 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2402 break;
2403 }
2404 case OP_RETURN_WIDE: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002405 int vSrc = mir->dalvikInsn.vA;
2406 int reg0 = selectFirstRegister(cUnit, vSrc, true);
2407 int reg1 = NEXT_REG(reg0);
2408 int rScratch = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002409 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002410 loadValuePair(cUnit, vSrc, reg0, reg1);
2411 storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
2412 storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002413 genReturnCommon(cUnit,mir);
2414 break;
2415 }
2416 case OP_RETURN:
2417 case OP_RETURN_OBJECT: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002418 int vSrc = mir->dalvikInsn.vA;
2419 int reg0 = selectFirstRegister(cUnit, vSrc, false);
2420 int rScratch = NEXT_REG(reg0);
2421 loadValue(cUnit, vSrc, reg0);
2422 storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
2423 reg0, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002424 genReturnCommon(cUnit,mir);
2425 break;
2426 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002427 case OP_MONITOR_ENTER:
2428 case OP_MONITOR_EXIT: {
2429 int offset = offsetof(InterpState, self);
2430 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002431 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002432 if (dalvikOpCode == OP_MONITOR_ENTER) {
2433 loadConstant(cUnit, r2, (int)dvmLockObject);
2434 } else {
2435 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2436 }
Ben Chenge9695e52009-06-16 16:11:47 -07002437 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002438 /* Do the call */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002439 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002440 break;
2441 }
2442 case OP_THROW: {
2443 genInterpSingleStep(cUnit, mir);
2444 break;
2445 }
2446 default:
2447 return true;
2448 }
2449 return false;
2450}
2451
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002452static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002453{
2454 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002455
Ben Chengba4fc8b2009-06-01 13:00:29 -07002456 float __aeabi_i2f( int op1 );
2457 int __aeabi_f2iz( float op1 );
2458 float __aeabi_d2f( double op1 );
2459 double __aeabi_f2d( float op1 );
2460 double __aeabi_i2d( int op1 );
2461 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002462 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002463 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002464 s8 dvmJitf2l( float op1 );
2465 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002466
Bill Buzbeed45ba372009-06-15 17:00:57 -07002467 switch (opCode) {
2468 case OP_INT_TO_FLOAT:
2469 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2470 case OP_FLOAT_TO_INT:
2471 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2472 case OP_DOUBLE_TO_FLOAT:
2473 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2474 case OP_FLOAT_TO_DOUBLE:
2475 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2476 case OP_INT_TO_DOUBLE:
2477 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2478 case OP_DOUBLE_TO_INT:
2479 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2480 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002481 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002482 case OP_LONG_TO_FLOAT:
2483 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2484 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002485 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002486 case OP_LONG_TO_DOUBLE:
2487 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2488 default:
2489 return true;
2490 }
2491 return false;
2492}
2493
2494static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2495{
2496 OpCode opCode = mir->dalvikInsn.opCode;
2497 int vSrc1Dest = mir->dalvikInsn.vA;
2498 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002499 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002500
Ben Chengba4fc8b2009-06-01 13:00:29 -07002501 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2502 return genArithOp( cUnit, mir );
2503 }
2504
Ben Chenge9695e52009-06-16 16:11:47 -07002505 /*
2506 * If data type is 64-bit, re-calculate the register numbers in the
2507 * corresponding cases.
2508 */
2509 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2510 reg1 = NEXT_REG(reg0);
2511 reg2 = NEXT_REG(reg1);
2512
Ben Chengba4fc8b2009-06-01 13:00:29 -07002513 switch (opCode) {
2514 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002515 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002516 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002517 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002518 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002519 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002520 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002521 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002522 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002523 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002524 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002525 case OP_NEG_INT:
2526 case OP_NOT_INT:
2527 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2528 case OP_NEG_LONG:
2529 case OP_NOT_LONG:
2530 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2531 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002532 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002533 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002534 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07002535 case OP_MOVE_WIDE: {
2536 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2537 reg1 = NEXT_REG(reg0);
2538 reg2 = NEXT_REG(reg1);
2539
2540 loadValuePair(cUnit, vSrc2, reg0, reg1);
2541 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002542 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002543 }
2544 case OP_INT_TO_LONG: {
2545 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2546 reg1 = NEXT_REG(reg0);
2547 reg2 = NEXT_REG(reg1);
2548
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002549 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002550 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002551 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002552 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002553 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002554 case OP_MOVE:
2555 case OP_MOVE_OBJECT:
2556 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002557 loadValue(cUnit, vSrc2, reg0);
2558 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002559 break;
2560 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07002561 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002562 opRegReg(cUnit, OP_2BYTE, reg1, reg0);
2563 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002564 break;
2565 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07002566 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002567 opRegReg(cUnit, OP_2SHORT, reg1, reg0);
2568 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002569 break;
2570 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07002571 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002572 opRegReg(cUnit, OP_2CHAR, reg1, reg0);
2573 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002574 break;
2575 case OP_ARRAY_LENGTH: {
2576 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002577 loadValue(cUnit, vSrc2, reg1);
2578 genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
2579 loadWordDisp(cUnit, reg1, lenOffset, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -07002580 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002581 break;
2582 }
2583 default:
2584 return true;
2585 }
2586 return false;
2587}
2588
2589static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2590{
2591 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07002592 int reg0, reg1, reg2;
2593
Ben Chengba4fc8b2009-06-01 13:00:29 -07002594 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2595 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002596 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002597 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002598
2599 reg0 = selectFirstRegister(cUnit, vNone, true);
2600 reg1 = NEXT_REG(reg0);
2601 reg2 = NEXT_REG(reg1);
2602
2603 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002604 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002605
2606 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07002607 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002608 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002609 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002610 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002611
Ben Chenge9695e52009-06-16 16:11:47 -07002612 reg0 = selectFirstRegister(cUnit, vNone, false);
2613 reg1 = NEXT_REG(reg0);
2614
2615 loadConstant(cUnit, reg0, BBBB);
2616 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002617 } else {
2618 return true;
2619 }
2620 return false;
2621}
2622
2623/* Compare agaist zero */
2624static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002625 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002626{
2627 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002628 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002629 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002630
Ben Chenge9695e52009-06-16 16:11:47 -07002631 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002632 opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002633
Bill Buzbee270c1d62009-08-13 16:58:07 -07002634//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002635 switch (dalvikOpCode) {
2636 case OP_IF_EQZ:
2637 cond = ARM_COND_EQ;
2638 break;
2639 case OP_IF_NEZ:
2640 cond = ARM_COND_NE;
2641 break;
2642 case OP_IF_LTZ:
2643 cond = ARM_COND_LT;
2644 break;
2645 case OP_IF_GEZ:
2646 cond = ARM_COND_GE;
2647 break;
2648 case OP_IF_GTZ:
2649 cond = ARM_COND_GT;
2650 break;
2651 case OP_IF_LEZ:
2652 cond = ARM_COND_LE;
2653 break;
2654 default:
2655 cond = 0;
2656 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2657 dvmAbort();
2658 }
2659 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2660 /* This mostly likely will be optimized away in a later phase */
2661 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2662 return false;
2663}
2664
2665static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2666{
2667 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2668 int vSrc = mir->dalvikInsn.vB;
2669 int vDest = mir->dalvikInsn.vA;
2670 int lit = mir->dalvikInsn.vC;
Ben Cheng4f489172009-09-27 17:08:35 -07002671 OpKind op = 0; /* Make gcc happy */
Ben Chenge9695e52009-06-16 16:11:47 -07002672 int reg0, reg1, regDest;
2673
2674 reg0 = selectFirstRegister(cUnit, vSrc, false);
2675 reg1 = NEXT_REG(reg0);
2676 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002677
Ben Chengba4fc8b2009-06-01 13:00:29 -07002678 int __aeabi_idivmod(int op1, int op2);
2679 int __aeabi_idiv(int op1, int op2);
2680
2681 switch (dalvikOpCode) {
2682 case OP_ADD_INT_LIT8:
2683 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002684 loadValue(cUnit, vSrc, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002685 opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
2686 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002687 break;
2688
2689 case OP_RSUB_INT_LIT8:
2690 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002691 loadValue(cUnit, vSrc, reg1);
2692 loadConstant(cUnit, reg0, lit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002693 opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
2694 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002695 break;
2696
2697 case OP_MUL_INT_LIT8:
2698 case OP_MUL_INT_LIT16:
2699 case OP_AND_INT_LIT8:
2700 case OP_AND_INT_LIT16:
2701 case OP_OR_INT_LIT8:
2702 case OP_OR_INT_LIT16:
2703 case OP_XOR_INT_LIT8:
2704 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002705 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002706 switch (dalvikOpCode) {
2707 case OP_MUL_INT_LIT8:
2708 case OP_MUL_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002709 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002710 break;
2711 case OP_AND_INT_LIT8:
2712 case OP_AND_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002713 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002714 break;
2715 case OP_OR_INT_LIT8:
2716 case OP_OR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002717 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002718 break;
2719 case OP_XOR_INT_LIT8:
2720 case OP_XOR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002721 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002722 break;
2723 default:
2724 dvmAbort();
2725 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002726 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2727 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002728 break;
2729
2730 case OP_SHL_INT_LIT8:
2731 case OP_SHR_INT_LIT8:
2732 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002733 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002734 switch (dalvikOpCode) {
2735 case OP_SHL_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002736 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002737 break;
2738 case OP_SHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002739 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002740 break;
2741 case OP_USHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002742 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002743 break;
2744 default: dvmAbort();
2745 }
Bill Buzbeea6f40f12009-09-22 09:45:41 -07002746 if (lit != 0) {
2747 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2748 storeValue(cUnit, regDest, vDest, reg1);
2749 } else {
2750 storeValue(cUnit, reg0, vDest, reg1);
2751 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002752 break;
2753
2754 case OP_DIV_INT_LIT8:
2755 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002756 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002757 if (lit == 0) {
2758 /* Let the interpreter deal with div by 0 */
2759 genInterpSingleStep(cUnit, mir);
2760 return false;
2761 }
2762 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2763 loadConstant(cUnit, r1, lit);
2764 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002765 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002766 storeValue(cUnit, r0, vDest, r2);
2767 break;
2768
2769 case OP_REM_INT_LIT8:
2770 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002771 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002772 if (lit == 0) {
2773 /* Let the interpreter deal with div by 0 */
2774 genInterpSingleStep(cUnit, mir);
2775 return false;
2776 }
2777 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2778 loadConstant(cUnit, r1, lit);
2779 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002780 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002781 storeValue(cUnit, r1, vDest, r2);
2782 break;
2783 default:
2784 return true;
2785 }
2786 return false;
2787}
2788
2789static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2790{
2791 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2792 int fieldOffset;
2793
2794 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2795 InstField *pInstField = (InstField *)
2796 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2797 int fieldOffset;
2798
2799 assert(pInstField != NULL);
2800 fieldOffset = pInstField->byteOffset;
2801 } else {
2802 /* To make the compiler happy */
2803 fieldOffset = 0;
2804 }
2805 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002806 case OP_NEW_ARRAY: {
2807 void *classPtr = (void*)
2808 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2809 assert(classPtr != NULL);
2810 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2811 loadConstant(cUnit, r0, (int) classPtr );
2812 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Ben Cheng4f489172009-09-27 17:08:35 -07002813 /*
2814 * "len < 0": bail to the interpreter to re-execute the
2815 * instruction
2816 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002817 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002818 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2819 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002820 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2821 opReg(cUnit, OP_BLX, r4PC);
Ben Cheng4f489172009-09-27 17:08:35 -07002822 /* generate a branch over if allocation is successful */
2823 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
2824 ArmLIR *branchOver = opCondBranch(cUnit, ARM_COND_NE);
2825 /*
2826 * OOM exception needs to be thrown here and cannot re-execute
2827 */
2828 loadConstant(cUnit, r0,
2829 (int) (cUnit->method->insns + mir->offset));
2830 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2831 /* noreturn */
2832
2833 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
2834 target->defMask = ENCODE_ALL;
2835 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002836 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2837 break;
2838 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002839 case OP_INSTANCE_OF: {
2840 ClassObject *classPtr =
2841 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2842 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002843 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002844 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002845//TUNING: compare to 0 primative to allow use of CB[N]Z
2846 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002847 /* When taken r0 has NULL which can be used for store directly */
Ben Cheng4f489172009-09-27 17:08:35 -07002848 ArmLIR *branch1 = opCondBranch(cUnit, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002849 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002850 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002851 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002852 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002853 opRegReg(cUnit, OP_CMP, r1, r2);
Ben Cheng4f489172009-09-27 17:08:35 -07002854 ArmLIR *branch2 = opCondBranch(cUnit, ARM_COND_EQ);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002855 opRegReg(cUnit, OP_MOV, r0, r1);
2856 opRegReg(cUnit, OP_MOV, r1, r2);
2857 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002858 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002859 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengd7d426a2009-09-22 11:23:36 -07002860 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002861 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2862 branch1->generic.target = (LIR *)target;
2863 branch2->generic.target = (LIR *)target;
2864 break;
2865 }
2866 case OP_IGET_WIDE:
2867 genIGetWide(cUnit, mir, fieldOffset);
2868 break;
2869 case OP_IGET:
2870 case OP_IGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002871 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002872 break;
2873 case OP_IGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002874 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002875 break;
2876 case OP_IGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002877 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002878 break;
2879 case OP_IGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002880 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002881 break;
2882 case OP_IGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002883 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002884 break;
2885 case OP_IPUT_WIDE:
2886 genIPutWide(cUnit, mir, fieldOffset);
2887 break;
2888 case OP_IPUT:
2889 case OP_IPUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002890 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002891 break;
2892 case OP_IPUT_SHORT:
2893 case OP_IPUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002894 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002895 break;
2896 case OP_IPUT_BYTE:
2897 case OP_IPUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002898 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002899 break;
2900 default:
2901 return true;
2902 }
2903 return false;
2904}
2905
2906static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2907{
2908 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2909 int fieldOffset = mir->dalvikInsn.vC;
2910 switch (dalvikOpCode) {
2911 case OP_IGET_QUICK:
2912 case OP_IGET_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002913 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002914 break;
2915 case OP_IPUT_QUICK:
2916 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002917 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002918 break;
2919 case OP_IGET_WIDE_QUICK:
2920 genIGetWide(cUnit, mir, fieldOffset);
2921 break;
2922 case OP_IPUT_WIDE_QUICK:
2923 genIPutWide(cUnit, mir, fieldOffset);
2924 break;
2925 default:
2926 return true;
2927 }
2928 return false;
2929
2930}
2931
2932/* Compare agaist zero */
2933static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002934 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002935{
2936 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002937 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002938 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002939
Ben Chenge9695e52009-06-16 16:11:47 -07002940 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2941 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2942 reg1 = NEXT_REG(reg0);
2943 /* Load vB first since vA can be fetched via a move */
2944 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2945 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2946 } else {
2947 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2948 reg1 = NEXT_REG(reg0);
2949 /* Load vA first since vB can be fetched via a move */
2950 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2951 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2952 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002953 opRegReg(cUnit, OP_CMP, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002954
2955 switch (dalvikOpCode) {
2956 case OP_IF_EQ:
2957 cond = ARM_COND_EQ;
2958 break;
2959 case OP_IF_NE:
2960 cond = ARM_COND_NE;
2961 break;
2962 case OP_IF_LT:
2963 cond = ARM_COND_LT;
2964 break;
2965 case OP_IF_GE:
2966 cond = ARM_COND_GE;
2967 break;
2968 case OP_IF_GT:
2969 cond = ARM_COND_GT;
2970 break;
2971 case OP_IF_LE:
2972 cond = ARM_COND_LE;
2973 break;
2974 default:
2975 cond = 0;
2976 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2977 dvmAbort();
2978 }
2979 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2980 /* This mostly likely will be optimized away in a later phase */
2981 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2982 return false;
2983}
2984
2985static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2986{
2987 OpCode opCode = mir->dalvikInsn.opCode;
2988 int vSrc1Dest = mir->dalvikInsn.vA;
2989 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002990 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002991
2992 switch (opCode) {
2993 case OP_MOVE_16:
2994 case OP_MOVE_OBJECT_16:
2995 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002996 case OP_MOVE_OBJECT_FROM16: {
2997 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2998 reg1 = NEXT_REG(reg0);
2999 loadValue(cUnit, vSrc2, reg0);
3000 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003001 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003002 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003003 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07003004 case OP_MOVE_WIDE_FROM16: {
3005 reg0 = selectFirstRegister(cUnit, vSrc2, true);
3006 reg1 = NEXT_REG(reg0);
3007 reg2 = NEXT_REG(reg1);
3008 loadValuePair(cUnit, vSrc2, reg0, reg1);
3009 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003010 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003011 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003012 default:
3013 return true;
3014 }
3015 return false;
3016}
3017
3018static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
3019{
3020 OpCode opCode = mir->dalvikInsn.opCode;
3021 int vA = mir->dalvikInsn.vA;
3022 int vB = mir->dalvikInsn.vB;
3023 int vC = mir->dalvikInsn.vC;
3024
Ben Chenge9695e52009-06-16 16:11:47 -07003025 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003026 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
3027 return genArithOp( cUnit, mir );
3028 }
3029
3030 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07003031 case OP_CMPL_FLOAT:
3032 case OP_CMPG_FLOAT:
3033 case OP_CMPL_DOUBLE:
3034 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003035 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003036 case OP_CMP_LONG:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07003037 genCmpLong(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003038 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003039 case OP_AGET_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003040 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003041 break;
3042 case OP_AGET:
3043 case OP_AGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003044 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003045 break;
3046 case OP_AGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003047 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003048 break;
3049 case OP_AGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003050 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003051 break;
3052 case OP_AGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003053 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003054 break;
3055 case OP_AGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003056 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003057 break;
3058 case OP_APUT_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003059 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003060 break;
3061 case OP_APUT:
3062 case OP_APUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003063 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003064 break;
3065 case OP_APUT_SHORT:
3066 case OP_APUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003067 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003068 break;
3069 case OP_APUT_BYTE:
3070 case OP_APUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003071 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003072 break;
3073 default:
3074 return true;
3075 }
3076 return false;
3077}
3078
3079static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
3080{
3081 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3082 switch (dalvikOpCode) {
3083 case OP_FILL_ARRAY_DATA: {
3084 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
3085 loadValue(cUnit, mir->dalvikInsn.vA, r0);
3086 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
3087 (int) (cUnit->method->insns + mir->offset));
3088 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07003089 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07003090 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003091 break;
3092 }
3093 /*
3094 * TODO
3095 * - Add a 1 to 3-entry per-location cache here to completely
3096 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
3097 * - Use out-of-line handlers for both of these
3098 */
3099 case OP_PACKED_SWITCH:
3100 case OP_SPARSE_SWITCH: {
3101 if (dalvikOpCode == OP_PACKED_SWITCH) {
3102 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
3103 } else {
3104 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
3105 }
3106 loadValue(cUnit, mir->dalvikInsn.vA, r1);
3107 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
3108 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07003109 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003110 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07003111 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3112 jitToInterpEntries.dvmJitToInterpNoChain), r2);
3113 opRegReg(cUnit, OP_ADD, r0, r0);
3114 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
3115 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003116 break;
3117 }
3118 default:
3119 return true;
3120 }
3121 return false;
3122}
3123
3124static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003125 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003126{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003127 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003128 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003129
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003130 if (bb->fallThrough != NULL)
3131 retChainingCell = &labelList[bb->fallThrough->id];
3132
Ben Chengba4fc8b2009-06-01 13:00:29 -07003133 DecodedInstruction *dInsn = &mir->dalvikInsn;
3134 switch (mir->dalvikInsn.opCode) {
3135 /*
3136 * calleeMethod = this->clazz->vtable[
3137 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3138 * ]
3139 */
3140 case OP_INVOKE_VIRTUAL:
3141 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003142 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003143 int methodIndex =
3144 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3145 methodIndex;
3146
3147 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3148 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3149 else
3150 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3151
Ben Cheng38329f52009-07-07 14:19:20 -07003152 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3153 retChainingCell,
3154 predChainingCell,
3155 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003156 break;
3157 }
3158 /*
3159 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3160 * ->pResMethods[BBBB]->methodIndex]
3161 */
3162 /* TODO - not excersized in RunPerf.jar */
3163 case OP_INVOKE_SUPER:
3164 case OP_INVOKE_SUPER_RANGE: {
3165 int mIndex = cUnit->method->clazz->pDvmDex->
3166 pResMethods[dInsn->vB]->methodIndex;
3167 const Method *calleeMethod =
3168 cUnit->method->clazz->super->vtable[mIndex];
3169
3170 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3171 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3172 else
3173 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3174
3175 /* r0 = calleeMethod */
3176 loadConstant(cUnit, r0, (int) calleeMethod);
3177
Ben Cheng38329f52009-07-07 14:19:20 -07003178 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3179 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003180 break;
3181 }
3182 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3183 case OP_INVOKE_DIRECT:
3184 case OP_INVOKE_DIRECT_RANGE: {
3185 const Method *calleeMethod =
3186 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3187
3188 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3189 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3190 else
3191 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3192
3193 /* r0 = calleeMethod */
3194 loadConstant(cUnit, r0, (int) calleeMethod);
3195
Ben Cheng38329f52009-07-07 14:19:20 -07003196 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3197 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003198 break;
3199 }
3200 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3201 case OP_INVOKE_STATIC:
3202 case OP_INVOKE_STATIC_RANGE: {
3203 const Method *calleeMethod =
3204 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3205
3206 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3207 genProcessArgsNoRange(cUnit, mir, dInsn,
3208 NULL /* no null check */);
3209 else
3210 genProcessArgsRange(cUnit, mir, dInsn,
3211 NULL /* no null check */);
3212
3213 /* r0 = calleeMethod */
3214 loadConstant(cUnit, r0, (int) calleeMethod);
3215
Ben Cheng38329f52009-07-07 14:19:20 -07003216 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3217 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003218 break;
3219 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07003220/*
3221 * TODO: When we move to using upper registers in Thumb2, make sure
3222 * the register allocater is told that r9, r10, & r12 are killed
3223 * here.
3224 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003225 /*
3226 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3227 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003228 *
3229 * Given "invoke-interface {v0}", the following is the generated code:
3230 *
3231 * 0x426a9abe : ldr r0, [r5, #0] --+
3232 * 0x426a9ac0 : mov r7, r5 |
3233 * 0x426a9ac2 : sub r7, #24 |
3234 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3235 * 0x426a9ac6 : beq 0x426a9afe |
3236 * 0x426a9ac8 : stmia r7, <r0> --+
3237 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3238 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3239 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3240 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3241 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3242 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3243 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
3244 * 0x426a9ad8 : mov r9, r1 --+
3245 * 0x426a9ada : mov r10, r2 |
3246 * 0x426a9adc : mov r12, r3 |
3247 * 0x426a9ade : mov r0, r3 |
3248 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3249 * 0x426a9ae2 : ldr r2, [pc, #76] |
3250 * 0x426a9ae4 : ldr r3, [pc, #68] |
3251 * 0x426a9ae6 : ldr r7, [pc, #64] |
3252 * 0x426a9ae8 : blx r7 --+
3253 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
3254 * 0x426a9aec : cmp r1, #0 --> compare against 0
3255 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3256 * 0x426a9af0 : ldr r7, [r6, #96] --+
3257 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3258 * 0x426a9af4 : mov r3, r12 |
3259 * 0x426a9af6 : blx r7 --+
3260 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3261 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3262 * 0x426a9afc : blx_2 see above --+
3263 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3264 * 0x426a9afe (0042): ldr r0, [pc, #52]
3265 * Exception_Handling:
3266 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3267 * 0x426a9b02 (0046): blx r1
3268 * 0x426a9b04 (0048): .align4
3269 * -------- chaining cell (hot): 0x0021
3270 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3271 * 0x426a9b06 (004a): blx r0
3272 * 0x426a9b08 (004c): data 0x7872(30834)
3273 * 0x426a9b0a (004e): data 0x428b(17035)
3274 * 0x426a9b0c (0050): .align4
3275 * -------- chaining cell (predicted)
3276 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3277 * 0x426a9b0e (0052): data 0x0000(0)
3278 * 0x426a9b10 (0054): data 0x0000(0) --> class
3279 * 0x426a9b12 (0056): data 0x0000(0)
3280 * 0x426a9b14 (0058): data 0x0000(0) --> method
3281 * 0x426a9b16 (005a): data 0x0000(0)
3282 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3283 * 0x426a9b1a (005e): data 0x0000(0)
3284 * 0x426a9b28 (006c): .word (0xad0392a5)
3285 * 0x426a9b2c (0070): .word (0x6e750)
3286 * 0x426a9b30 (0074): .word (0x4109a618)
3287 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003288 */
3289 case OP_INVOKE_INTERFACE:
3290 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003291 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003292 int methodIndex = dInsn->vB;
3293
3294 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3295 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3296 else
3297 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3298
Ben Cheng38329f52009-07-07 14:19:20 -07003299 /* "this" is already left in r0 by genProcessArgs* */
3300
3301 /* r4PC = dalvikCallsite */
3302 loadConstant(cUnit, r4PC,
3303 (int) (cUnit->method->insns + mir->offset));
3304
3305 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003306 ArmLIR *addrRetChain =
3307 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003308 addrRetChain->generic.target = (LIR *) retChainingCell;
3309
3310 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003311 ArmLIR *predictedChainingCell =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003312 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003313 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3314
3315 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3316
3317 /* return through lr - jump to the chaining cell */
3318 genUnconditionalBranch(cUnit, predChainingCell);
3319
3320 /*
3321 * null-check on "this" may have been eliminated, but we still need
3322 * a PC-reconstruction label for stack overflow bailout.
3323 */
3324 if (pcrLabel == NULL) {
3325 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003326 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3327 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003328 pcrLabel->operands[0] = dPC;
3329 pcrLabel->operands[1] = mir->offset;
3330 /* Insert the place holder to the growable list */
3331 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3332 }
3333
3334 /* return through lr+2 - punt to the interpreter */
3335 genUnconditionalBranch(cUnit, pcrLabel);
3336
3337 /*
3338 * return through lr+4 - fully resolve the callee method.
3339 * r1 <- count
3340 * r2 <- &predictedChainCell
3341 * r3 <- this->class
3342 * r4 <- dPC
3343 * r7 <- this->class->vtable
3344 */
3345
3346 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003347 opRegReg(cUnit, OP_MOV, r9, r1);
3348 opRegReg(cUnit, OP_MOV, r10, r2);
3349 opRegReg(cUnit, OP_MOV, r12, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003350
Ben Chengba4fc8b2009-06-01 13:00:29 -07003351 /* r0 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003352 opRegReg(cUnit, OP_MOV, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003353
3354 /* r1 = BBBB */
3355 loadConstant(cUnit, r1, dInsn->vB);
3356
3357 /* r2 = method (caller) */
3358 loadConstant(cUnit, r2, (int) cUnit->method);
3359
3360 /* r3 = pDvmDex */
3361 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3362
3363 loadConstant(cUnit, r7,
3364 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003365 opReg(cUnit, OP_BLX, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003366
3367 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3368
Bill Buzbee270c1d62009-08-13 16:58:07 -07003369 opRegReg(cUnit, OP_MOV, r1, r9);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003370
Ben Cheng38329f52009-07-07 14:19:20 -07003371 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003372 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003373
Ben Cheng4f489172009-09-27 17:08:35 -07003374 ArmLIR *bypassRechaining = opCondBranch(cUnit, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07003375
Bill Buzbee270c1d62009-08-13 16:58:07 -07003376 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3377 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003378
Bill Buzbee270c1d62009-08-13 16:58:07 -07003379 opRegReg(cUnit, OP_MOV, r2, r10);
3380 opRegReg(cUnit, OP_MOV, r3, r12);
Ben Cheng38329f52009-07-07 14:19:20 -07003381
3382 /*
3383 * r0 = calleeMethod
3384 * r2 = &predictedChainingCell
3385 * r3 = class
3386 *
3387 * &returnChainingCell has been loaded into r1 but is not needed
3388 * when patching the chaining cell and will be clobbered upon
3389 * returning so it will be reconstructed again.
3390 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003391 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003392
3393 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003394 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003395 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003396
3397 bypassRechaining->generic.target = (LIR *) addrRetChain;
3398
Ben Chengba4fc8b2009-06-01 13:00:29 -07003399 /*
3400 * r0 = this, r1 = calleeMethod,
3401 * r1 = &ChainingCell,
3402 * r4PC = callsiteDPC,
3403 */
3404 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3405#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003406 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003407#endif
3408 /* Handle exceptions using the interpreter */
3409 genTrap(cUnit, mir->offset, pcrLabel);
3410 break;
3411 }
3412 /* NOP */
3413 case OP_INVOKE_DIRECT_EMPTY: {
3414 return false;
3415 }
3416 case OP_FILLED_NEW_ARRAY:
3417 case OP_FILLED_NEW_ARRAY_RANGE: {
3418 /* Just let the interpreter deal with these */
3419 genInterpSingleStep(cUnit, mir);
3420 break;
3421 }
3422 default:
3423 return true;
3424 }
3425 return false;
3426}
3427
3428static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003429 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003430{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003431 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3432 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3433 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003434
3435 DecodedInstruction *dInsn = &mir->dalvikInsn;
3436 switch (mir->dalvikInsn.opCode) {
3437 /* calleeMethod = this->clazz->vtable[BBBB] */
3438 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3439 case OP_INVOKE_VIRTUAL_QUICK: {
3440 int methodIndex = dInsn->vB;
3441 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3442 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3443 else
3444 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3445
Ben Cheng38329f52009-07-07 14:19:20 -07003446 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3447 retChainingCell,
3448 predChainingCell,
3449 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003450 break;
3451 }
3452 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3453 case OP_INVOKE_SUPER_QUICK:
3454 case OP_INVOKE_SUPER_QUICK_RANGE: {
3455 const Method *calleeMethod =
3456 cUnit->method->clazz->super->vtable[dInsn->vB];
3457
3458 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3459 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3460 else
3461 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3462
3463 /* r0 = calleeMethod */
3464 loadConstant(cUnit, r0, (int) calleeMethod);
3465
Ben Cheng38329f52009-07-07 14:19:20 -07003466 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3467 calleeMethod);
3468 /* Handle exceptions using the interpreter */
3469 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003470 break;
3471 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003472 default:
3473 return true;
3474 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003475 return false;
3476}
3477
3478/*
3479 * NOTE: We assume here that the special native inline routines
3480 * are side-effect free. By making this assumption, we can safely
3481 * re-execute the routine from the interpreter if it decides it
3482 * wants to throw an exception. We still need to EXPORT_PC(), though.
3483 */
3484static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3485{
3486 DecodedInstruction *dInsn = &mir->dalvikInsn;
3487 switch( mir->dalvikInsn.opCode) {
3488 case OP_EXECUTE_INLINE: {
3489 unsigned int i;
3490 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003491 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003492 int operation = dInsn->vB;
3493
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003494 switch (operation) {
3495 case INLINE_EMPTYINLINEMETHOD:
3496 return false; /* Nop */
3497 case INLINE_STRING_LENGTH:
3498 return genInlinedStringLength(cUnit, mir);
3499 case INLINE_MATH_ABS_INT:
3500 return genInlinedAbsInt(cUnit, mir);
3501 case INLINE_MATH_ABS_LONG:
3502 return genInlinedAbsLong(cUnit, mir);
3503 case INLINE_MATH_MIN_INT:
3504 return genInlinedMinMaxInt(cUnit, mir, true);
3505 case INLINE_MATH_MAX_INT:
3506 return genInlinedMinMaxInt(cUnit, mir, false);
3507 case INLINE_STRING_CHARAT:
3508 return genInlinedStringCharAt(cUnit, mir);
3509 case INLINE_MATH_SQRT:
3510 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003511 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003512 else
3513 break; /* Handle with C routine */
3514 case INLINE_MATH_COS:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003515 case INLINE_MATH_SIN:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003516 break; /* Handle with C routine */
3517 case INLINE_MATH_ABS_FLOAT:
3518 return genInlinedAbsFloat(cUnit, mir);
3519 case INLINE_MATH_ABS_DOUBLE:
3520 return genInlinedAbsDouble(cUnit, mir);
3521 case INLINE_STRING_COMPARETO:
3522 case INLINE_STRING_EQUALS:
Bill Buzbee12ba0152009-09-03 14:03:09 -07003523 case INLINE_STRING_INDEXOF_I:
3524 case INLINE_STRING_INDEXOF_II:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003525 break;
3526 default:
3527 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003528 }
3529
3530 /* Materialize pointer to retval & push */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003531 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3532 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3533
Ben Chengba4fc8b2009-06-01 13:00:29 -07003534 /* Push r4 and (just to take up space) r5) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003535 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003536
3537 /* Get code pointer to inline routine */
3538 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3539
3540 /* Export PC */
3541 genExportPC(cUnit, mir, r0, r1 );
3542
3543 /* Load arguments to r0 through r3 as applicable */
3544 for (i=0; i < dInsn->vA; i++) {
3545 loadValue(cUnit, dInsn->arg[i], i);
3546 }
3547 /* Call inline routine */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003548 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003549
3550 /* Strip frame */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003551 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003552
3553 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003554 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003555
Ben Chenge9695e52009-06-16 16:11:47 -07003556 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003557 break;
3558 }
3559 default:
3560 return true;
3561 }
3562 return false;
3563}
3564
3565static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3566{
3567 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3568 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3569 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3570 return false;
3571}
3572
Ben Chengba4fc8b2009-06-01 13:00:29 -07003573/*
3574 * The following are special processing routines that handle transfer of
3575 * controls between compiled code and the interpreter. Certain VM states like
3576 * Dalvik PC and special-purpose registers are reconstructed here.
3577 */
3578
Ben Cheng1efc9c52009-06-08 18:25:27 -07003579/* Chaining cell for code that may need warmup. */
3580static void handleNormalChainingCell(CompilationUnit *cUnit,
3581 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003582{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003583 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3584 jitToInterpEntries.dvmJitToInterpNormal), r0);
3585 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003586 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3587}
3588
3589/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003590 * Chaining cell for instructions that immediately following already translated
3591 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003592 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003593static void handleHotChainingCell(CompilationUnit *cUnit,
3594 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003595{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003596 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3597 jitToInterpEntries.dvmJitToTraceSelect), r0);
3598 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003599 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3600}
3601
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003602#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003603/* Chaining cell for branches that branch back into the same basic block */
3604static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3605 unsigned int offset)
3606{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003607#if defined(WITH_SELF_VERIFICATION)
Jeff Hao97319a82009-08-12 16:57:15 -07003608 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3609 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003610#else
3611 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3612 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3613#endif
Jeff Hao97319a82009-08-12 16:57:15 -07003614 newLIR1(cUnit, THUMB_BLX_R, r0);
3615 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3616}
3617
3618#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003619/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003620static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3621 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003622{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003623 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3624 jitToInterpEntries.dvmJitToTraceSelect), r0);
3625 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003626 addWordData(cUnit, (int) (callee->insns), true);
3627}
3628
Ben Cheng38329f52009-07-07 14:19:20 -07003629/* Chaining cell for monomorphic method invocations. */
3630static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3631{
3632
3633 /* Should not be executed in the initial state */
3634 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3635 /* To be filled: class */
3636 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3637 /* To be filled: method */
3638 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3639 /*
3640 * Rechain count. The initial value of 0 here will trigger chaining upon
3641 * the first invocation of this callsite.
3642 */
3643 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3644}
3645
Ben Chengba4fc8b2009-06-01 13:00:29 -07003646/* Load the Dalvik PC into r0 and jump to the specified target */
3647static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003648 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003649{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003650 ArmLIR **pcrLabel =
3651 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003652 int numElems = cUnit->pcReconstructionList.numUsed;
3653 int i;
3654 for (i = 0; i < numElems; i++) {
3655 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3656 /* r0 = dalvik PC */
3657 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3658 genUnconditionalBranch(cUnit, targetLabel);
3659 }
3660}
3661
Ben Cheng4238ec22009-08-24 16:32:22 -07003662static char *extendedMIROpNames[MIR_OP_LAST - MIR_OP_FIRST] = {
3663 "MIR_OP_PHI",
3664 "MIR_OP_NULL_N_RANGE_UP_CHECK",
3665 "MIR_OP_NULL_N_RANGE_DOWN_CHECK",
3666 "MIR_OP_LOWER_BOUND_CHECK",
3667 "MIR_OP_PUNT",
3668};
3669
3670/*
3671 * vA = arrayReg;
3672 * vB = idxReg;
3673 * vC = endConditionReg;
3674 * arg[0] = maxC
3675 * arg[1] = minC
3676 * arg[2] = loopBranchConditionCode
3677 */
3678static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3679{
3680 DecodedInstruction *dInsn = &mir->dalvikInsn;
3681 const int lenOffset = offsetof(ArrayObject, length);
3682 const int regArray = 0;
3683 const int regIdxEnd = NEXT_REG(regArray);
3684 const int regLength = regArray;
3685 const int maxC = dInsn->arg[0];
3686 const int minC = dInsn->arg[1];
3687
3688 /* regArray <- arrayRef */
3689 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3690 loadValue(cUnit, mir->dalvikInsn.vC, regIdxEnd);
3691 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3692 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3693
3694 /* regLength <- len(arrayRef) */
3695 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3696
3697 int delta = maxC;
3698 /*
3699 * If the loop end condition is ">=" instead of ">", then the largest value
3700 * of the index is "endCondition - 1".
3701 */
3702 if (dInsn->arg[2] == OP_IF_GE) {
3703 delta--;
3704 }
3705
3706 if (delta) {
3707 opRegImm(cUnit, OP_ADD, regIdxEnd, delta, regIdxEnd);
3708 }
3709 /* Punt if "regIdxEnd < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003710 genRegRegCheck(cUnit, ARM_COND_GE, regIdxEnd, regLength, 0,
3711 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003712}
3713
3714/*
3715 * vA = arrayReg;
3716 * vB = idxReg;
3717 * vC = endConditionReg;
3718 * arg[0] = maxC
3719 * arg[1] = minC
3720 * arg[2] = loopBranchConditionCode
3721 */
3722static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3723{
3724 DecodedInstruction *dInsn = &mir->dalvikInsn;
3725 const int lenOffset = offsetof(ArrayObject, length);
3726 const int regArray = 0;
3727 const int regIdxInit = NEXT_REG(regArray);
3728 const int regLength = regArray;
3729 const int maxC = dInsn->arg[0];
3730 const int minC = dInsn->arg[1];
3731
3732 /* regArray <- arrayRef */
3733 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3734 loadValue(cUnit, mir->dalvikInsn.vB, regIdxInit);
3735 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3736 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3737
3738 /* regLength <- len(arrayRef) */
3739 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3740
3741 if (maxC) {
3742 opRegImm(cUnit, OP_ADD, regIdxInit, maxC, regIdxInit);
3743 }
3744
3745 /* Punt if "regIdxInit < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003746 genRegRegCheck(cUnit, ARM_COND_GE, regIdxInit, regLength, 0,
3747 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003748}
3749
3750/*
3751 * vA = idxReg;
3752 * vB = minC;
3753 */
3754static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3755{
3756 DecodedInstruction *dInsn = &mir->dalvikInsn;
3757 const int regIdx = 0;
3758 const int minC = dInsn->vB;
3759
3760 /* regIdx <- initial index value */
3761 loadValue(cUnit, mir->dalvikInsn.vA, regIdx);
3762
3763 /* Punt if "regIdxInit + minC >= 0" is false */
3764 genRegImmCheck(cUnit, ARM_COND_LT, regIdx, -minC, 0,
3765 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3766}
3767
3768/* Extended MIR instructions like PHI */
3769static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3770{
3771 int opOffset = mir->dalvikInsn.opCode - MIR_OP_FIRST;
3772 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3773 false);
3774 strcpy(msg, extendedMIROpNames[opOffset]);
3775 newLIR1(cUnit, ARM_PSEUDO_EXTENDED_MIR, (int) msg);
3776
3777 switch (mir->dalvikInsn.opCode) {
3778 case MIR_OP_PHI: {
3779 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3780 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3781 break;
3782 }
3783 case MIR_OP_NULL_N_RANGE_UP_CHECK: {
3784 genHoistedChecksForCountUpLoop(cUnit, mir);
3785 break;
3786 }
3787 case MIR_OP_NULL_N_RANGE_DOWN_CHECK: {
3788 genHoistedChecksForCountDownLoop(cUnit, mir);
3789 break;
3790 }
3791 case MIR_OP_LOWER_BOUND_CHECK: {
3792 genHoistedLowerBoundCheck(cUnit, mir);
3793 break;
3794 }
3795 case MIR_OP_PUNT: {
3796 genUnconditionalBranch(cUnit,
3797 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3798 break;
3799 }
3800 default:
3801 break;
3802 }
3803}
3804
3805/*
3806 * Create a PC-reconstruction cell for the starting offset of this trace.
3807 * Since the PCR cell is placed near the end of the compiled code which is
3808 * usually out of range for a conditional branch, we put two branches (one
3809 * branch over to the loop body and one layover branch to the actual PCR) at the
3810 * end of the entry block.
3811 */
3812static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3813 ArmLIR *bodyLabel)
3814{
3815 /* Set up the place holder to reconstruct this Dalvik PC */
3816 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3817 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
3818 pcrLabel->operands[0] =
3819 (int) (cUnit->method->insns + entry->startOffset);
3820 pcrLabel->operands[1] = entry->startOffset;
3821 /* Insert the place holder to the growable list */
3822 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3823
3824 /*
3825 * Next, create two branches - one branch over to the loop body and the
3826 * other branch to the PCR cell to punt.
3827 */
3828 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3829 branchToBody->opCode = THUMB_B_UNCOND;
3830 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003831 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07003832 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3833
3834 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3835 branchToPCR->opCode = THUMB_B_UNCOND;
3836 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003837 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003838 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3839}
3840
Ben Chengba4fc8b2009-06-01 13:00:29 -07003841void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3842{
3843 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003844 ArmLIR *labelList =
3845 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003846 GrowableList chainingListByType[CHAINING_CELL_LAST];
3847 int i;
3848
3849 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003850 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003851 */
3852 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3853 dvmInitGrowableList(&chainingListByType[i], 2);
3854 }
3855
3856 BasicBlock **blockList = cUnit->blockList;
3857
Bill Buzbee6e963e12009-06-17 16:56:19 -07003858 if (cUnit->executionCount) {
3859 /*
3860 * Reserve 6 bytes at the beginning of the trace
3861 * +----------------------------+
3862 * | execution count (4 bytes) |
3863 * +----------------------------+
3864 * | chain cell offset (2 bytes)|
3865 * +----------------------------+
3866 * ...and then code to increment the execution
3867 * count:
3868 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3869 * sub r0, #10 @ back up to addr of executionCount
3870 * ldr r1, [r0]
3871 * add r1, #1
3872 * str r1, [r0]
3873 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003874 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3875 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003876 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003877 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003878 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003879 /* Thumb instruction used directly here to ensure correct size */
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003880 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003881 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3882 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3883 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3884 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003885 } else {
3886 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003887 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003888 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003889 cUnit->headerSize = 2;
3890 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003891
Ben Chengba4fc8b2009-06-01 13:00:29 -07003892 /* Handle the content in each basic block */
3893 for (i = 0; i < cUnit->numBlocks; i++) {
3894 blockList[i]->visited = true;
3895 MIR *mir;
3896
3897 labelList[i].operands[0] = blockList[i]->startOffset;
3898
3899 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3900 /*
3901 * Append the label pseudo LIR first. Chaining cells will be handled
3902 * separately afterwards.
3903 */
3904 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3905 }
3906
Ben Cheng4238ec22009-08-24 16:32:22 -07003907 if (blockList[i]->blockType == ENTRY_BLOCK) {
3908 labelList[i].opCode = ARM_PSEUDO_ENTRY_BLOCK;
3909 if (blockList[i]->firstMIRInsn == NULL) {
3910 continue;
3911 } else {
3912 setupLoopEntryBlock(cUnit, blockList[i],
3913 &labelList[blockList[i]->fallThrough->id]);
3914 }
3915 } else if (blockList[i]->blockType == EXIT_BLOCK) {
3916 labelList[i].opCode = ARM_PSEUDO_EXIT_BLOCK;
3917 goto gen_fallthrough;
3918 } else if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003919 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003920 /* Reset the register state */
3921 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003922 } else {
3923 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003924 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003925 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003926 /* handle the codegen later */
3927 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003928 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003929 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003930 case CHAINING_CELL_INVOKE_SINGLETON:
3931 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003932 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003933 labelList[i].operands[0] =
3934 (int) blockList[i]->containingMethod;
3935 /* handle the codegen later */
3936 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003937 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3938 (void *) i);
3939 break;
3940 case CHAINING_CELL_INVOKE_PREDICTED:
3941 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003942 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003943 /* handle the codegen later */
3944 dvmInsertGrowableList(
3945 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3946 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003947 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003948 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003949 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003950 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003951 /* handle the codegen later */
3952 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003953 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003954 (void *) i);
3955 break;
3956 case PC_RECONSTRUCTION:
3957 /* Make sure exception handling block is next */
3958 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003959 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003960 assert (i == cUnit->numBlocks - 2);
3961 handlePCReconstruction(cUnit, &labelList[i+1]);
3962 break;
3963 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003964 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003965 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003966 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3967 jitToInterpEntries.dvmJitToInterpPunt),
3968 r1);
3969 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003970 }
3971 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003972#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003973 case CHAINING_CELL_BACKWARD_BRANCH:
3974 labelList[i].opCode =
3975 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3976 /* handle the codegen later */
3977 dvmInsertGrowableList(
3978 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3979 (void *) i);
3980 break;
3981#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003982 default:
3983 break;
3984 }
3985 continue;
3986 }
Ben Chenge9695e52009-06-16 16:11:47 -07003987
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003988 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003989
Ben Chengba4fc8b2009-06-01 13:00:29 -07003990 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003991 if (mir->dalvikInsn.opCode >= MIR_OP_FIRST) {
3992 handleExtendedMIR(cUnit, mir);
3993 continue;
3994 }
3995
Ben Chengba4fc8b2009-06-01 13:00:29 -07003996 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3997 InstructionFormat dalvikFormat =
3998 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003999 ArmLIR *boundaryLIR =
4000 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Cheng4238ec22009-08-24 16:32:22 -07004001 mir->offset, dalvikOpCode);
4002 if (mir->ssaRep) {
4003 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
4004 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
4005 }
4006
Ben Chenge9695e52009-06-16 16:11:47 -07004007 /* Remember the first LIR for this block */
4008 if (headLIR == NULL) {
4009 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07004010 /* Set the first boundaryLIR as a scheduling barrier */
4011 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07004012 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004013
Ben Chengba4fc8b2009-06-01 13:00:29 -07004014 bool notHandled;
4015 /*
4016 * Debugging: screen the opcode first to see if it is in the
4017 * do[-not]-compile list
4018 */
4019 bool singleStepMe =
4020 gDvmJit.includeSelectedOp !=
4021 ((gDvmJit.opList[dalvikOpCode >> 3] &
4022 (1 << (dalvikOpCode & 0x7))) !=
4023 0);
Jeff Hao97319a82009-08-12 16:57:15 -07004024#if defined(WITH_SELF_VERIFICATION)
4025 /* Punt on opcodes we can't replay */
4026 if (selfVerificationPuntOps(dalvikOpCode))
4027 singleStepMe = true;
4028#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004029 if (singleStepMe || cUnit->allSingleStep) {
4030 notHandled = false;
4031 genInterpSingleStep(cUnit, mir);
4032 } else {
4033 opcodeCoverage[dalvikOpCode]++;
4034 switch (dalvikFormat) {
4035 case kFmt10t:
4036 case kFmt20t:
4037 case kFmt30t:
4038 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4039 mir, blockList[i], labelList);
4040 break;
4041 case kFmt10x:
4042 notHandled = handleFmt10x(cUnit, mir);
4043 break;
4044 case kFmt11n:
4045 case kFmt31i:
4046 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4047 break;
4048 case kFmt11x:
4049 notHandled = handleFmt11x(cUnit, mir);
4050 break;
4051 case kFmt12x:
4052 notHandled = handleFmt12x(cUnit, mir);
4053 break;
4054 case kFmt20bc:
4055 notHandled = handleFmt20bc(cUnit, mir);
4056 break;
4057 case kFmt21c:
4058 case kFmt31c:
4059 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4060 break;
4061 case kFmt21h:
4062 notHandled = handleFmt21h(cUnit, mir);
4063 break;
4064 case kFmt21s:
4065 notHandled = handleFmt21s(cUnit, mir);
4066 break;
4067 case kFmt21t:
4068 notHandled = handleFmt21t(cUnit, mir, blockList[i],
4069 labelList);
4070 break;
4071 case kFmt22b:
4072 case kFmt22s:
4073 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4074 break;
4075 case kFmt22c:
4076 notHandled = handleFmt22c(cUnit, mir);
4077 break;
4078 case kFmt22cs:
4079 notHandled = handleFmt22cs(cUnit, mir);
4080 break;
4081 case kFmt22t:
4082 notHandled = handleFmt22t(cUnit, mir, blockList[i],
4083 labelList);
4084 break;
4085 case kFmt22x:
4086 case kFmt32x:
4087 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4088 break;
4089 case kFmt23x:
4090 notHandled = handleFmt23x(cUnit, mir);
4091 break;
4092 case kFmt31t:
4093 notHandled = handleFmt31t(cUnit, mir);
4094 break;
4095 case kFmt3rc:
4096 case kFmt35c:
4097 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4098 labelList);
4099 break;
4100 case kFmt3rms:
4101 case kFmt35ms:
4102 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4103 labelList);
4104 break;
4105 case kFmt3inline:
4106 notHandled = handleFmt3inline(cUnit, mir);
4107 break;
4108 case kFmt51l:
4109 notHandled = handleFmt51l(cUnit, mir);
4110 break;
4111 default:
4112 notHandled = true;
4113 break;
4114 }
4115 }
4116 if (notHandled) {
4117 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4118 mir->offset,
4119 dalvikOpCode, getOpcodeName(dalvikOpCode),
4120 dalvikFormat);
4121 dvmAbort();
4122 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004123 }
4124 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004125
4126 if (blockList[i]->blockType == ENTRY_BLOCK) {
4127 dvmCompilerAppendLIR(cUnit,
4128 (LIR *) cUnit->loopAnalysis->branchToBody);
4129 dvmCompilerAppendLIR(cUnit,
4130 (LIR *) cUnit->loopAnalysis->branchToPCR);
4131 }
4132
4133 if (headLIR) {
4134 /*
4135 * Eliminate redundant loads/stores and delay stores into later
4136 * slots
4137 */
4138 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4139 cUnit->lastLIRInsn);
4140 }
4141
4142gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004143 /*
4144 * Check if the block is terminated due to trace length constraint -
4145 * insert an unconditional branch to the chaining cell.
4146 */
4147 if (blockList[i]->needFallThroughBranch) {
4148 genUnconditionalBranch(cUnit,
4149 &labelList[blockList[i]->fallThrough->id]);
4150 }
4151
Ben Chengba4fc8b2009-06-01 13:00:29 -07004152 }
4153
Ben Chenge9695e52009-06-16 16:11:47 -07004154 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07004155 for (i = 0; i < CHAINING_CELL_LAST; i++) {
4156 size_t j;
4157 int *blockIdList = (int *) chainingListByType[i].elemList;
4158
4159 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4160
4161 /* No chaining cells of this type */
4162 if (cUnit->numChainingCells[i] == 0)
4163 continue;
4164
4165 /* Record the first LIR for a new type of chaining cell */
4166 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4167
4168 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4169 int blockId = blockIdList[j];
4170
4171 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004172 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004173
4174 /* Insert the pseudo chaining instruction */
4175 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4176
4177
4178 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07004179 case CHAINING_CELL_NORMAL:
4180 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004181 blockList[blockId]->startOffset);
4182 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004183 case CHAINING_CELL_INVOKE_SINGLETON:
4184 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004185 blockList[blockId]->containingMethod);
4186 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004187 case CHAINING_CELL_INVOKE_PREDICTED:
4188 handleInvokePredictedChainingCell(cUnit);
4189 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07004190 case CHAINING_CELL_HOT:
4191 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004192 blockList[blockId]->startOffset);
4193 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004194#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07004195 case CHAINING_CELL_BACKWARD_BRANCH:
4196 handleBackwardBranchChainingCell(cUnit,
4197 blockList[blockId]->startOffset);
4198 break;
4199#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004200 default:
4201 dvmAbort();
4202 break;
4203 }
4204 }
4205 }
Ben Chenge9695e52009-06-16 16:11:47 -07004206
4207 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004208}
4209
4210/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004211bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004212{
Bill Buzbee716f1202009-07-23 13:22:09 -07004213 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004214
4215 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07004216 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004217 }
4218
4219 switch (work->kind) {
4220 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07004221 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004222 break;
4223 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004224 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07004225 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004226 break;
4227 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07004228 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004229 dvmAbort();
4230 }
4231 return res;
4232}
4233
Ben Chengba4fc8b2009-06-01 13:00:29 -07004234/* Architectural-specific debugging helpers go here */
4235void dvmCompilerArchDump(void)
4236{
4237 /* Print compiled opcode in this VM instance */
4238 int i, start, streak;
4239 char buf[1024];
4240
4241 streak = i = 0;
4242 buf[0] = 0;
4243 while (opcodeCoverage[i] == 0 && i < 256) {
4244 i++;
4245 }
4246 if (i == 256) {
4247 return;
4248 }
4249 for (start = i++, streak = 1; i < 256; i++) {
4250 if (opcodeCoverage[i]) {
4251 streak++;
4252 } else {
4253 if (streak == 1) {
4254 sprintf(buf+strlen(buf), "%x,", start);
4255 } else {
4256 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4257 }
4258 streak = 0;
4259 while (opcodeCoverage[i] == 0 && i < 256) {
4260 i++;
4261 }
4262 if (i < 256) {
4263 streak = 1;
4264 start = i;
4265 }
4266 }
4267 }
4268 if (streak) {
4269 if (streak == 1) {
4270 sprintf(buf+strlen(buf), "%x", start);
4271 } else {
4272 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4273 }
4274 }
4275 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004276 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004277 }
4278}
Ben Chengd7d426a2009-09-22 11:23:36 -07004279
4280/* Common initialization routine for an architecture family */
4281bool dvmCompilerArchInit()
4282{
4283 int i;
4284
4285 for (i = 0; i < ARM_LAST; i++) {
4286 if (EncodingMap[i].opCode != i) {
4287 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4288 EncodingMap[i].name, i, EncodingMap[i].opCode);
4289 dvmAbort();
4290 }
4291 }
4292
4293 return compilerArchVariantInit();
4294}