blob: d65023d6bbd395aa8d8f9d19fcffee3d814efb14 [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);
813 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
814 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
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001854 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001855 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001856
Bill Buzbee270c1d62009-08-13 16:58:07 -07001857 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1858 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001859
1860 /*
1861 * r0 = calleeMethod
1862 * r2 = &predictedChainingCell
1863 * r3 = class
1864 *
1865 * &returnChainingCell has been loaded into r1 but is not needed
1866 * when patching the chaining cell and will be clobbered upon
1867 * returning so it will be reconstructed again.
1868 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001869 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001870
1871 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001872 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001873 addrRetChain->generic.target = (LIR *) retChainingCell;
1874
1875 bypassRechaining->generic.target = (LIR *) addrRetChain;
1876 /*
1877 * r0 = calleeMethod,
1878 * r1 = &ChainingCell,
1879 * r4PC = callsiteDPC,
1880 */
1881 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1882#if defined(INVOKE_STATS)
1883 gDvmJit.invokePredictedChain++;
1884#endif
1885 /* Handle exceptions using the interpreter */
1886 genTrap(cUnit, mir->offset, pcrLabel);
1887}
1888
1889/*
1890 * Up calling this function, "this" is stored in r0. The actual class will be
1891 * chased down off r0 and the predicted one will be retrieved through
1892 * predictedChainingCell then a comparison is performed to see whether the
1893 * previously established chaining is still valid.
1894 *
1895 * The return LIR is a branch based on the comparison result. The actual branch
1896 * target will be setup in the caller.
1897 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001898static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1899 ArmLIR *predChainingCell,
1900 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001901 MIR *mir)
1902{
1903 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001904 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001905
1906 /*
1907 * r2 now contains predicted class. The starting offset of the
1908 * cached value is 4 bytes into the chaining cell.
1909 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001910 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001911 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07001912 getPredictedClass->generic.target = (LIR *) predChainingCell;
1913
1914 /*
1915 * r0 now contains predicted method. The starting offset of the
1916 * cached value is 8 bytes into the chaining cell.
1917 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001918 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001919 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001920 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1921
1922 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001923 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001924 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001925 getRechainingRequestCount->generic.target =
1926 (LIR *) predChainingCell;
1927
1928 /* r4PC = dalvikCallsite */
1929 loadConstant(cUnit, r4PC,
1930 (int) (cUnit->method->insns + mir->offset));
1931
1932 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001933 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001934 addrRetChain->generic.target = (LIR *) retChainingCell;
1935
1936 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001937 opRegReg(cUnit, OP_CMP, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001938
Bill Buzbee270c1d62009-08-13 16:58:07 -07001939 return opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001940}
1941
Ben Chengba4fc8b2009-06-01 13:00:29 -07001942/* Geneate a branch to go back to the interpreter */
1943static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1944{
1945 /* r0 = dalvik pc */
1946 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001947 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1948 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1949 jitToInterpEntries.dvmJitToInterpPunt), r1);
1950 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001951}
1952
1953/*
1954 * Attempt to single step one instruction using the interpreter and return
1955 * to the compiled code for the next Dalvik instruction
1956 */
1957static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1958{
1959 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1960 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1961 kInstrCanThrow;
1962 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1963 genPuntToInterp(cUnit, mir->offset);
1964 return;
1965 }
1966 int entryAddr = offsetof(InterpState,
1967 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001968 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001969 /* r0 = dalvik pc */
1970 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1971 /* r1 = dalvik pc of following instruction */
1972 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001973 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001974}
1975
Bill Buzbee270c1d62009-08-13 16:58:07 -07001976/* Generate conditional branch instructions */
1977static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1978 ArmConditionCode cond,
1979 ArmLIR *target)
1980{
1981 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
1982 branch->generic.target = (LIR *) target;
1983 return branch;
1984}
Ben Chengba4fc8b2009-06-01 13:00:29 -07001985
Bill Buzbee270c1d62009-08-13 16:58:07 -07001986/* Generate unconditional branch instructions */
1987static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1988{
1989 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
1990 branch->generic.target = (LIR *) target;
1991 return branch;
1992}
1993
1994/* Load the address of a Dalvik register on the frame */
1995static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
1996{
1997 return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
1998}
1999
2000/* Load a single value from rFP[src] and store them into rDest */
2001static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
2002{
2003 return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
2004}
2005
2006/* Load a word at base + displacement. Displacement must be word multiple */
2007static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
2008 int rDest)
2009{
2010 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
2011 -1);
2012}
2013
2014static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
2015 int displacement, int rSrc, int rScratch)
2016{
2017 return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
2018}
2019
2020/* Store a value from rSrc to vDest */
2021static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
2022 int rScratch)
2023{
2024 killNullCheckedRegister(cUnit, vDest);
2025 updateLiveRegister(cUnit, vDest, rSrc);
2026 return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
2027}
2028/*
2029 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
2030 * rDestHi
2031 */
2032static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
2033 int rDestHi)
2034{
2035 ArmLIR *res;
2036 /* Use reg + imm5*4 to load the values if possible */
2037 if (vSrc <= 30) {
2038 res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
2039 loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
2040 } else {
2041 assert(rDestLo < rDestHi);
2042 res = loadValueAddress(cUnit, vSrc, rDestLo);
Ben Chengd7d426a2009-09-22 11:23:36 -07002043 /*
2044 * Protect the loadMultiple instruction from being reordered with other
2045 * Dalvik stack accesses.
2046 */
2047 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002048 loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
Ben Chengd7d426a2009-09-22 11:23:36 -07002049 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002050 }
2051 return res;
2052}
2053
2054/*
2055 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
2056 * vDest+1
2057 */
2058static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
2059 int vDest, int rScratch)
2060{
2061 ArmLIR *res;
2062 killNullCheckedRegister(cUnit, vDest);
2063 killNullCheckedRegister(cUnit, vDest+1);
2064 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
2065
2066 /* Use reg + imm5*4 to store the values if possible */
2067 if (vDest <= 30) {
2068 res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
2069 storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
2070 } else {
2071 assert(rSrcLo < rSrcHi);
2072 res = loadValueAddress(cUnit, vDest, rScratch);
Ben Chengd7d426a2009-09-22 11:23:36 -07002073 /*
2074 * Protect the storeMultiple instruction from being reordered with
2075 * other Dalvik stack accesses.
2076 */
2077 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002078 storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
Ben Chengd7d426a2009-09-22 11:23:36 -07002079 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002080 }
2081 return res;
2082}
2083
2084static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
2085{
2086 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
2087 dvmCompilerAppendLIR(cUnit, (LIR*)res);
2088 return res;
2089}
2090
Ben Chengba4fc8b2009-06-01 13:00:29 -07002091/*
2092 * The following are the first-level codegen routines that analyze the format
2093 * of each bytecode then either dispatch special purpose codegen routines
2094 * or produce corresponding Thumb instructions directly.
2095 */
2096
2097static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002098 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002099{
2100 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2101 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2102 return false;
2103}
2104
2105static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
2106{
2107 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2108 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
2109 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
2110 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2111 return true;
2112 }
2113 switch (dalvikOpCode) {
2114 case OP_RETURN_VOID:
2115 genReturnCommon(cUnit,mir);
2116 break;
2117 case OP_UNUSED_73:
2118 case OP_UNUSED_79:
2119 case OP_UNUSED_7A:
2120 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2121 return true;
2122 case OP_NOP:
2123 break;
2124 default:
2125 return true;
2126 }
2127 return false;
2128}
2129
2130static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2131{
Ben Chenge9695e52009-06-16 16:11:47 -07002132 int reg0, reg1, reg2;
2133
Ben Chengba4fc8b2009-06-01 13:00:29 -07002134 switch (mir->dalvikInsn.opCode) {
2135 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07002136 case OP_CONST_4: {
2137 /* Avoid using the previously used register */
2138 reg0 = selectFirstRegister(cUnit, vNone, false);
2139 reg1 = NEXT_REG(reg0);
2140 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
2141 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002142 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002143 }
2144 case OP_CONST_WIDE_32: {
2145 /* Avoid using the previously used register */
2146 reg0 = selectFirstRegister(cUnit, vNone, true);
2147 reg1 = NEXT_REG(reg0);
2148 reg2 = NEXT_REG(reg1);
2149 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002150 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002151 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002152 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002153 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002154 default:
2155 return true;
2156 }
2157 return false;
2158}
2159
2160static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2161{
Ben Chenge9695e52009-06-16 16:11:47 -07002162 int reg0, reg1, reg2;
2163
2164 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002165 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07002166 case OP_CONST_HIGH16: {
2167 reg0 = selectFirstRegister(cUnit, vNone, false);
2168 reg1 = NEXT_REG(reg0);
2169 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
2170 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002171 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002172 }
2173 case OP_CONST_WIDE_HIGH16: {
2174 reg0 = selectFirstRegister(cUnit, vNone, true);
2175 reg1 = NEXT_REG(reg0);
2176 reg2 = NEXT_REG(reg1);
2177 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
2178 loadConstant(cUnit, reg0, 0);
2179 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002180 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002181 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002182 default:
2183 return true;
2184 }
2185 return false;
2186}
2187
2188static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2189{
2190 /* For OP_THROW_VERIFICATION_ERROR */
2191 genInterpSingleStep(cUnit, mir);
2192 return false;
2193}
2194
2195static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2196{
Ben Chenge9695e52009-06-16 16:11:47 -07002197 /* Native register to use if the interested value is vA */
2198 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2199 /* Native register to use if source is not from Dalvik registers */
2200 int regvNone = selectFirstRegister(cUnit, vNone, false);
2201 /* Similar to regvA but for 64-bit values */
2202 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
2203 /* Similar to regvNone but for 64-bit values */
2204 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
2205
Ben Chengba4fc8b2009-06-01 13:00:29 -07002206 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002207 case OP_CONST_STRING_JUMBO:
2208 case OP_CONST_STRING: {
2209 void *strPtr = (void*)
2210 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2211 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002212 loadConstant(cUnit, regvNone, (int) strPtr );
2213 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002214 break;
2215 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002216 case OP_CONST_CLASS: {
2217 void *classPtr = (void*)
2218 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2219 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002220 loadConstant(cUnit, regvNone, (int) classPtr );
2221 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002222 break;
2223 }
2224 case OP_SGET_OBJECT:
2225 case OP_SGET_BOOLEAN:
2226 case OP_SGET_CHAR:
2227 case OP_SGET_BYTE:
2228 case OP_SGET_SHORT:
2229 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002230 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002231 void *fieldPtr = (void*)
2232 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2233 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002234 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002235#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002236 loadWordDisp(cUnit, regvNone, 0, regvNone);
Jeff Hao97319a82009-08-12 16:57:15 -07002237#else
2238 int regMap = regvNone << 4 | regvNone;
2239 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2240
Jeff Hao97319a82009-08-12 16:57:15 -07002241#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002242 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002243 break;
2244 }
2245 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002246 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002247 void *fieldPtr = (void*)
2248 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002249 int reg0, reg1, reg2;
2250
Ben Chengba4fc8b2009-06-01 13:00:29 -07002251 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002252 reg0 = regvNoneWide;
2253 reg1 = NEXT_REG(reg0);
2254 reg2 = NEXT_REG(reg1);
2255 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002256#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002257 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002258#else
2259 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2260 selfVerificationMemOpWrapper(cUnit, regMap,
2261 &selfVerificationLoadDoubleword);
2262
Jeff Hao97319a82009-08-12 16:57:15 -07002263#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002264 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002265 break;
2266 }
2267 case OP_SPUT_OBJECT:
2268 case OP_SPUT_BOOLEAN:
2269 case OP_SPUT_CHAR:
2270 case OP_SPUT_BYTE:
2271 case OP_SPUT_SHORT:
2272 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002273 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002274 void *fieldPtr = (void*)
2275 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002276
Ben Chengba4fc8b2009-06-01 13:00:29 -07002277 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002278 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
2279 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
2280 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002281#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002282 storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
Jeff Hao97319a82009-08-12 16:57:15 -07002283#else
2284 int regMap = regvA << 4 | NEXT_REG(regvA);
2285 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2286#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002287 break;
2288 }
2289 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002290 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002291 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002292 void *fieldPtr = (void*)
2293 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002294
Ben Chengba4fc8b2009-06-01 13:00:29 -07002295 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002296 reg0 = regvAWide;
2297 reg1 = NEXT_REG(reg0);
2298 reg2 = NEXT_REG(reg1);
2299 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2300 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2301 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002302#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002303 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002304#else
2305 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2306 selfVerificationMemOpWrapper(cUnit, regMap,
2307 &selfVerificationStoreDoubleword);
2308#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002309 break;
2310 }
2311 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002312 /*
2313 * Obey the calling convention and don't mess with the register
2314 * usage.
2315 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002316 ClassObject *classPtr = (void*)
2317 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2318 assert(classPtr != NULL);
2319 assert(classPtr->status & CLASS_INITIALIZED);
2320 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
2321 /* It's going to throw, just let the interp. deal with it. */
2322 genInterpSingleStep(cUnit, mir);
2323 return false;
2324 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002325 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002326 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002327 genExportPC(cUnit, mir, r2, r3 );
2328 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002329 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002330 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002331 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2332 break;
2333 }
2334 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002335 /*
2336 * Obey the calling convention and don't mess with the register
2337 * usage.
2338 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002339 ClassObject *classPtr =
2340 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2341 loadConstant(cUnit, r1, (int) classPtr );
2342 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002343 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* Null? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002344 ArmLIR *branch1 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002345 opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002346 /* r0 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002347 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002348 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002349 opRegReg(cUnit, OP_CMP, r0, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002350 ArmLIR *branch2 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002351 opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2352 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002353 /* check cast failed - punt to the interpreter */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002354 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002355 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002356 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengd7d426a2009-09-22 11:23:36 -07002357 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002358 branch1->generic.target = (LIR *)target;
2359 branch2->generic.target = (LIR *)target;
2360 break;
2361 }
2362 default:
2363 return true;
2364 }
2365 return false;
2366}
2367
2368static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2369{
2370 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2371 switch (dalvikOpCode) {
2372 case OP_MOVE_EXCEPTION: {
2373 int offset = offsetof(InterpState, self);
2374 int exOffset = offsetof(Thread, exception);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002375 loadWordDisp(cUnit, rGLUE, offset, r1);
2376 loadWordDisp(cUnit, r1, exOffset, r0);
Ben Chenge9695e52009-06-16 16:11:47 -07002377 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002378 break;
2379 }
2380 case OP_MOVE_RESULT:
2381 case OP_MOVE_RESULT_OBJECT: {
2382 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002383 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002384 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2385 break;
2386 }
2387 case OP_MOVE_RESULT_WIDE: {
2388 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002389 loadWordDisp(cUnit, rGLUE, offset, r0);
2390 loadWordDisp(cUnit, rGLUE, offset+4, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002391 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2392 break;
2393 }
2394 case OP_RETURN_WIDE: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002395 int vSrc = mir->dalvikInsn.vA;
2396 int reg0 = selectFirstRegister(cUnit, vSrc, true);
2397 int reg1 = NEXT_REG(reg0);
2398 int rScratch = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002399 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002400 loadValuePair(cUnit, vSrc, reg0, reg1);
2401 storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
2402 storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002403 genReturnCommon(cUnit,mir);
2404 break;
2405 }
2406 case OP_RETURN:
2407 case OP_RETURN_OBJECT: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002408 int vSrc = mir->dalvikInsn.vA;
2409 int reg0 = selectFirstRegister(cUnit, vSrc, false);
2410 int rScratch = NEXT_REG(reg0);
2411 loadValue(cUnit, vSrc, reg0);
2412 storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
2413 reg0, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002414 genReturnCommon(cUnit,mir);
2415 break;
2416 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002417 case OP_MONITOR_ENTER:
2418 case OP_MONITOR_EXIT: {
2419 int offset = offsetof(InterpState, self);
2420 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002421 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002422 if (dalvikOpCode == OP_MONITOR_ENTER) {
2423 loadConstant(cUnit, r2, (int)dvmLockObject);
2424 } else {
2425 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2426 }
Ben Chenge9695e52009-06-16 16:11:47 -07002427 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002428 /* Do the call */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002429 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002430 break;
2431 }
2432 case OP_THROW: {
2433 genInterpSingleStep(cUnit, mir);
2434 break;
2435 }
2436 default:
2437 return true;
2438 }
2439 return false;
2440}
2441
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002442static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002443{
2444 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002445
Ben Chengba4fc8b2009-06-01 13:00:29 -07002446 float __aeabi_i2f( int op1 );
2447 int __aeabi_f2iz( float op1 );
2448 float __aeabi_d2f( double op1 );
2449 double __aeabi_f2d( float op1 );
2450 double __aeabi_i2d( int op1 );
2451 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002452 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002453 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002454 s8 dvmJitf2l( float op1 );
2455 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002456
Bill Buzbeed45ba372009-06-15 17:00:57 -07002457 switch (opCode) {
2458 case OP_INT_TO_FLOAT:
2459 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2460 case OP_FLOAT_TO_INT:
2461 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2462 case OP_DOUBLE_TO_FLOAT:
2463 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2464 case OP_FLOAT_TO_DOUBLE:
2465 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2466 case OP_INT_TO_DOUBLE:
2467 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2468 case OP_DOUBLE_TO_INT:
2469 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2470 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002471 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002472 case OP_LONG_TO_FLOAT:
2473 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2474 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002475 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002476 case OP_LONG_TO_DOUBLE:
2477 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2478 default:
2479 return true;
2480 }
2481 return false;
2482}
2483
2484static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2485{
2486 OpCode opCode = mir->dalvikInsn.opCode;
2487 int vSrc1Dest = mir->dalvikInsn.vA;
2488 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002489 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002490
Ben Chengba4fc8b2009-06-01 13:00:29 -07002491 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2492 return genArithOp( cUnit, mir );
2493 }
2494
Ben Chenge9695e52009-06-16 16:11:47 -07002495 /*
2496 * If data type is 64-bit, re-calculate the register numbers in the
2497 * corresponding cases.
2498 */
2499 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2500 reg1 = NEXT_REG(reg0);
2501 reg2 = NEXT_REG(reg1);
2502
Ben Chengba4fc8b2009-06-01 13:00:29 -07002503 switch (opCode) {
2504 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002505 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002506 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002507 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002508 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002509 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002510 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002511 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002512 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002513 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002514 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002515 case OP_NEG_INT:
2516 case OP_NOT_INT:
2517 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2518 case OP_NEG_LONG:
2519 case OP_NOT_LONG:
2520 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2521 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002522 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002523 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002524 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07002525 case OP_MOVE_WIDE: {
2526 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2527 reg1 = NEXT_REG(reg0);
2528 reg2 = NEXT_REG(reg1);
2529
2530 loadValuePair(cUnit, vSrc2, reg0, reg1);
2531 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002532 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002533 }
2534 case OP_INT_TO_LONG: {
2535 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2536 reg1 = NEXT_REG(reg0);
2537 reg2 = NEXT_REG(reg1);
2538
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002539 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002540 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002541 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002542 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002543 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002544 case OP_MOVE:
2545 case OP_MOVE_OBJECT:
2546 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002547 loadValue(cUnit, vSrc2, reg0);
2548 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002549 break;
2550 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07002551 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002552 opRegReg(cUnit, OP_2BYTE, reg1, reg0);
2553 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002554 break;
2555 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07002556 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002557 opRegReg(cUnit, OP_2SHORT, reg1, reg0);
2558 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002559 break;
2560 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07002561 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002562 opRegReg(cUnit, OP_2CHAR, reg1, reg0);
2563 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002564 break;
2565 case OP_ARRAY_LENGTH: {
2566 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002567 loadValue(cUnit, vSrc2, reg1);
2568 genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
2569 loadWordDisp(cUnit, reg1, lenOffset, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -07002570 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002571 break;
2572 }
2573 default:
2574 return true;
2575 }
2576 return false;
2577}
2578
2579static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2580{
2581 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07002582 int reg0, reg1, reg2;
2583
Ben Chengba4fc8b2009-06-01 13:00:29 -07002584 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2585 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002586 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002587 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002588
2589 reg0 = selectFirstRegister(cUnit, vNone, true);
2590 reg1 = NEXT_REG(reg0);
2591 reg2 = NEXT_REG(reg1);
2592
2593 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002594 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002595
2596 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07002597 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002598 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002599 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002600 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002601
Ben Chenge9695e52009-06-16 16:11:47 -07002602 reg0 = selectFirstRegister(cUnit, vNone, false);
2603 reg1 = NEXT_REG(reg0);
2604
2605 loadConstant(cUnit, reg0, BBBB);
2606 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002607 } else {
2608 return true;
2609 }
2610 return false;
2611}
2612
2613/* Compare agaist zero */
2614static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002615 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002616{
2617 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002618 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002619 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002620
Ben Chenge9695e52009-06-16 16:11:47 -07002621 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002622 opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002623
Bill Buzbee270c1d62009-08-13 16:58:07 -07002624//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002625 switch (dalvikOpCode) {
2626 case OP_IF_EQZ:
2627 cond = ARM_COND_EQ;
2628 break;
2629 case OP_IF_NEZ:
2630 cond = ARM_COND_NE;
2631 break;
2632 case OP_IF_LTZ:
2633 cond = ARM_COND_LT;
2634 break;
2635 case OP_IF_GEZ:
2636 cond = ARM_COND_GE;
2637 break;
2638 case OP_IF_GTZ:
2639 cond = ARM_COND_GT;
2640 break;
2641 case OP_IF_LEZ:
2642 cond = ARM_COND_LE;
2643 break;
2644 default:
2645 cond = 0;
2646 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2647 dvmAbort();
2648 }
2649 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2650 /* This mostly likely will be optimized away in a later phase */
2651 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2652 return false;
2653}
2654
2655static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2656{
2657 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2658 int vSrc = mir->dalvikInsn.vB;
2659 int vDest = mir->dalvikInsn.vA;
2660 int lit = mir->dalvikInsn.vC;
Bill Buzbee270c1d62009-08-13 16:58:07 -07002661 OpKind op;
Ben Chenge9695e52009-06-16 16:11:47 -07002662 int reg0, reg1, regDest;
2663
2664 reg0 = selectFirstRegister(cUnit, vSrc, false);
2665 reg1 = NEXT_REG(reg0);
2666 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002667
Ben Chengba4fc8b2009-06-01 13:00:29 -07002668 int __aeabi_idivmod(int op1, int op2);
2669 int __aeabi_idiv(int op1, int op2);
2670
2671 switch (dalvikOpCode) {
2672 case OP_ADD_INT_LIT8:
2673 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002674 loadValue(cUnit, vSrc, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002675 opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
2676 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002677 break;
2678
2679 case OP_RSUB_INT_LIT8:
2680 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002681 loadValue(cUnit, vSrc, reg1);
2682 loadConstant(cUnit, reg0, lit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002683 opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
2684 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002685 break;
2686
2687 case OP_MUL_INT_LIT8:
2688 case OP_MUL_INT_LIT16:
2689 case OP_AND_INT_LIT8:
2690 case OP_AND_INT_LIT16:
2691 case OP_OR_INT_LIT8:
2692 case OP_OR_INT_LIT16:
2693 case OP_XOR_INT_LIT8:
2694 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002695 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002696 switch (dalvikOpCode) {
2697 case OP_MUL_INT_LIT8:
2698 case OP_MUL_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002699 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002700 break;
2701 case OP_AND_INT_LIT8:
2702 case OP_AND_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002703 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002704 break;
2705 case OP_OR_INT_LIT8:
2706 case OP_OR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002707 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002708 break;
2709 case OP_XOR_INT_LIT8:
2710 case OP_XOR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002711 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002712 break;
2713 default:
2714 dvmAbort();
2715 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002716 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2717 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002718 break;
2719
2720 case OP_SHL_INT_LIT8:
2721 case OP_SHR_INT_LIT8:
2722 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002723 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002724 switch (dalvikOpCode) {
2725 case OP_SHL_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002726 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002727 break;
2728 case OP_SHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002729 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002730 break;
2731 case OP_USHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002732 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002733 break;
2734 default: dvmAbort();
2735 }
Bill Buzbeea6f40f12009-09-22 09:45:41 -07002736 if (lit != 0) {
2737 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2738 storeValue(cUnit, regDest, vDest, reg1);
2739 } else {
2740 storeValue(cUnit, reg0, vDest, reg1);
2741 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002742 break;
2743
2744 case OP_DIV_INT_LIT8:
2745 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002746 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002747 if (lit == 0) {
2748 /* Let the interpreter deal with div by 0 */
2749 genInterpSingleStep(cUnit, mir);
2750 return false;
2751 }
2752 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2753 loadConstant(cUnit, r1, lit);
2754 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002755 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002756 storeValue(cUnit, r0, vDest, r2);
2757 break;
2758
2759 case OP_REM_INT_LIT8:
2760 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002761 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002762 if (lit == 0) {
2763 /* Let the interpreter deal with div by 0 */
2764 genInterpSingleStep(cUnit, mir);
2765 return false;
2766 }
2767 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2768 loadConstant(cUnit, r1, lit);
2769 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002770 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002771 storeValue(cUnit, r1, vDest, r2);
2772 break;
2773 default:
2774 return true;
2775 }
2776 return false;
2777}
2778
2779static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2780{
2781 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2782 int fieldOffset;
2783
2784 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2785 InstField *pInstField = (InstField *)
2786 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2787 int fieldOffset;
2788
2789 assert(pInstField != NULL);
2790 fieldOffset = pInstField->byteOffset;
2791 } else {
2792 /* To make the compiler happy */
2793 fieldOffset = 0;
2794 }
2795 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002796 case OP_NEW_ARRAY: {
2797 void *classPtr = (void*)
2798 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2799 assert(classPtr != NULL);
2800 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2801 loadConstant(cUnit, r0, (int) classPtr );
2802 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002803 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002804 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2805 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002806 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2807 opReg(cUnit, OP_BLX, r4PC);
2808 /* Note: on failure, we'll bail and reinterpret */
Ben Chenge9695e52009-06-16 16:11:47 -07002809 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002810 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2811 break;
2812 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002813 case OP_INSTANCE_OF: {
2814 ClassObject *classPtr =
2815 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2816 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002817 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002818 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002819//TUNING: compare to 0 primative to allow use of CB[N]Z
2820 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002821 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002822 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002823 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002824 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002825 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002826 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002827 opRegReg(cUnit, OP_CMP, r1, r2);
2828 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2829 opRegReg(cUnit, OP_MOV, r0, r1);
2830 opRegReg(cUnit, OP_MOV, r1, r2);
2831 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002832 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002833 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengd7d426a2009-09-22 11:23:36 -07002834 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002835 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2836 branch1->generic.target = (LIR *)target;
2837 branch2->generic.target = (LIR *)target;
2838 break;
2839 }
2840 case OP_IGET_WIDE:
2841 genIGetWide(cUnit, mir, fieldOffset);
2842 break;
2843 case OP_IGET:
2844 case OP_IGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002845 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002846 break;
2847 case OP_IGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002848 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002849 break;
2850 case OP_IGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002851 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002852 break;
2853 case OP_IGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002854 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002855 break;
2856 case OP_IGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002857 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002858 break;
2859 case OP_IPUT_WIDE:
2860 genIPutWide(cUnit, mir, fieldOffset);
2861 break;
2862 case OP_IPUT:
2863 case OP_IPUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002864 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002865 break;
2866 case OP_IPUT_SHORT:
2867 case OP_IPUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002868 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002869 break;
2870 case OP_IPUT_BYTE:
2871 case OP_IPUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002872 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002873 break;
2874 default:
2875 return true;
2876 }
2877 return false;
2878}
2879
2880static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2881{
2882 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2883 int fieldOffset = mir->dalvikInsn.vC;
2884 switch (dalvikOpCode) {
2885 case OP_IGET_QUICK:
2886 case OP_IGET_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002887 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002888 break;
2889 case OP_IPUT_QUICK:
2890 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002891 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002892 break;
2893 case OP_IGET_WIDE_QUICK:
2894 genIGetWide(cUnit, mir, fieldOffset);
2895 break;
2896 case OP_IPUT_WIDE_QUICK:
2897 genIPutWide(cUnit, mir, fieldOffset);
2898 break;
2899 default:
2900 return true;
2901 }
2902 return false;
2903
2904}
2905
2906/* Compare agaist zero */
2907static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002908 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002909{
2910 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002911 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002912 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002913
Ben Chenge9695e52009-06-16 16:11:47 -07002914 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2915 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2916 reg1 = NEXT_REG(reg0);
2917 /* Load vB first since vA can be fetched via a move */
2918 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2919 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2920 } else {
2921 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2922 reg1 = NEXT_REG(reg0);
2923 /* Load vA first since vB can be fetched via a move */
2924 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2925 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2926 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002927 opRegReg(cUnit, OP_CMP, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002928
2929 switch (dalvikOpCode) {
2930 case OP_IF_EQ:
2931 cond = ARM_COND_EQ;
2932 break;
2933 case OP_IF_NE:
2934 cond = ARM_COND_NE;
2935 break;
2936 case OP_IF_LT:
2937 cond = ARM_COND_LT;
2938 break;
2939 case OP_IF_GE:
2940 cond = ARM_COND_GE;
2941 break;
2942 case OP_IF_GT:
2943 cond = ARM_COND_GT;
2944 break;
2945 case OP_IF_LE:
2946 cond = ARM_COND_LE;
2947 break;
2948 default:
2949 cond = 0;
2950 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2951 dvmAbort();
2952 }
2953 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2954 /* This mostly likely will be optimized away in a later phase */
2955 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2956 return false;
2957}
2958
2959static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2960{
2961 OpCode opCode = mir->dalvikInsn.opCode;
2962 int vSrc1Dest = mir->dalvikInsn.vA;
2963 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002964 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002965
2966 switch (opCode) {
2967 case OP_MOVE_16:
2968 case OP_MOVE_OBJECT_16:
2969 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002970 case OP_MOVE_OBJECT_FROM16: {
2971 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2972 reg1 = NEXT_REG(reg0);
2973 loadValue(cUnit, vSrc2, reg0);
2974 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002975 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002976 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002977 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002978 case OP_MOVE_WIDE_FROM16: {
2979 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2980 reg1 = NEXT_REG(reg0);
2981 reg2 = NEXT_REG(reg1);
2982 loadValuePair(cUnit, vSrc2, reg0, reg1);
2983 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002984 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002985 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002986 default:
2987 return true;
2988 }
2989 return false;
2990}
2991
2992static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2993{
2994 OpCode opCode = mir->dalvikInsn.opCode;
2995 int vA = mir->dalvikInsn.vA;
2996 int vB = mir->dalvikInsn.vB;
2997 int vC = mir->dalvikInsn.vC;
2998
Ben Chenge9695e52009-06-16 16:11:47 -07002999 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003000 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
3001 return genArithOp( cUnit, mir );
3002 }
3003
3004 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07003005 case OP_CMPL_FLOAT:
3006 case OP_CMPG_FLOAT:
3007 case OP_CMPL_DOUBLE:
3008 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003009 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003010 case OP_CMP_LONG:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07003011 genCmpLong(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003012 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003013 case OP_AGET_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003014 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003015 break;
3016 case OP_AGET:
3017 case OP_AGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003018 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003019 break;
3020 case OP_AGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003021 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003022 break;
3023 case OP_AGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003024 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003025 break;
3026 case OP_AGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003027 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003028 break;
3029 case OP_AGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003030 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003031 break;
3032 case OP_APUT_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003033 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003034 break;
3035 case OP_APUT:
3036 case OP_APUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003037 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003038 break;
3039 case OP_APUT_SHORT:
3040 case OP_APUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003041 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003042 break;
3043 case OP_APUT_BYTE:
3044 case OP_APUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003045 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003046 break;
3047 default:
3048 return true;
3049 }
3050 return false;
3051}
3052
3053static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
3054{
3055 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3056 switch (dalvikOpCode) {
3057 case OP_FILL_ARRAY_DATA: {
3058 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
3059 loadValue(cUnit, mir->dalvikInsn.vA, r0);
3060 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
3061 (int) (cUnit->method->insns + mir->offset));
3062 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07003063 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07003064 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003065 break;
3066 }
3067 /*
3068 * TODO
3069 * - Add a 1 to 3-entry per-location cache here to completely
3070 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
3071 * - Use out-of-line handlers for both of these
3072 */
3073 case OP_PACKED_SWITCH:
3074 case OP_SPARSE_SWITCH: {
3075 if (dalvikOpCode == OP_PACKED_SWITCH) {
3076 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
3077 } else {
3078 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
3079 }
3080 loadValue(cUnit, mir->dalvikInsn.vA, r1);
3081 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
3082 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07003083 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003084 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07003085 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3086 jitToInterpEntries.dvmJitToInterpNoChain), r2);
3087 opRegReg(cUnit, OP_ADD, r0, r0);
3088 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
3089 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003090 break;
3091 }
3092 default:
3093 return true;
3094 }
3095 return false;
3096}
3097
3098static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003099 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003100{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003101 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003102 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003103
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003104 if (bb->fallThrough != NULL)
3105 retChainingCell = &labelList[bb->fallThrough->id];
3106
Ben Chengba4fc8b2009-06-01 13:00:29 -07003107 DecodedInstruction *dInsn = &mir->dalvikInsn;
3108 switch (mir->dalvikInsn.opCode) {
3109 /*
3110 * calleeMethod = this->clazz->vtable[
3111 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3112 * ]
3113 */
3114 case OP_INVOKE_VIRTUAL:
3115 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003116 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003117 int methodIndex =
3118 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3119 methodIndex;
3120
3121 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3122 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3123 else
3124 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3125
Ben Cheng38329f52009-07-07 14:19:20 -07003126 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3127 retChainingCell,
3128 predChainingCell,
3129 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003130 break;
3131 }
3132 /*
3133 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3134 * ->pResMethods[BBBB]->methodIndex]
3135 */
3136 /* TODO - not excersized in RunPerf.jar */
3137 case OP_INVOKE_SUPER:
3138 case OP_INVOKE_SUPER_RANGE: {
3139 int mIndex = cUnit->method->clazz->pDvmDex->
3140 pResMethods[dInsn->vB]->methodIndex;
3141 const Method *calleeMethod =
3142 cUnit->method->clazz->super->vtable[mIndex];
3143
3144 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3145 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3146 else
3147 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3148
3149 /* r0 = calleeMethod */
3150 loadConstant(cUnit, r0, (int) calleeMethod);
3151
Ben Cheng38329f52009-07-07 14:19:20 -07003152 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3153 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003154 break;
3155 }
3156 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3157 case OP_INVOKE_DIRECT:
3158 case OP_INVOKE_DIRECT_RANGE: {
3159 const Method *calleeMethod =
3160 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3161
3162 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3163 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3164 else
3165 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3166
3167 /* r0 = calleeMethod */
3168 loadConstant(cUnit, r0, (int) calleeMethod);
3169
Ben Cheng38329f52009-07-07 14:19:20 -07003170 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3171 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003172 break;
3173 }
3174 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3175 case OP_INVOKE_STATIC:
3176 case OP_INVOKE_STATIC_RANGE: {
3177 const Method *calleeMethod =
3178 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3179
3180 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3181 genProcessArgsNoRange(cUnit, mir, dInsn,
3182 NULL /* no null check */);
3183 else
3184 genProcessArgsRange(cUnit, mir, dInsn,
3185 NULL /* no null check */);
3186
3187 /* r0 = calleeMethod */
3188 loadConstant(cUnit, r0, (int) calleeMethod);
3189
Ben Cheng38329f52009-07-07 14:19:20 -07003190 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3191 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003192 break;
3193 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07003194/*
3195 * TODO: When we move to using upper registers in Thumb2, make sure
3196 * the register allocater is told that r9, r10, & r12 are killed
3197 * here.
3198 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003199 /*
3200 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3201 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003202 *
3203 * Given "invoke-interface {v0}", the following is the generated code:
3204 *
3205 * 0x426a9abe : ldr r0, [r5, #0] --+
3206 * 0x426a9ac0 : mov r7, r5 |
3207 * 0x426a9ac2 : sub r7, #24 |
3208 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3209 * 0x426a9ac6 : beq 0x426a9afe |
3210 * 0x426a9ac8 : stmia r7, <r0> --+
3211 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3212 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3213 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3214 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3215 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3216 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3217 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
3218 * 0x426a9ad8 : mov r9, r1 --+
3219 * 0x426a9ada : mov r10, r2 |
3220 * 0x426a9adc : mov r12, r3 |
3221 * 0x426a9ade : mov r0, r3 |
3222 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3223 * 0x426a9ae2 : ldr r2, [pc, #76] |
3224 * 0x426a9ae4 : ldr r3, [pc, #68] |
3225 * 0x426a9ae6 : ldr r7, [pc, #64] |
3226 * 0x426a9ae8 : blx r7 --+
3227 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
3228 * 0x426a9aec : cmp r1, #0 --> compare against 0
3229 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3230 * 0x426a9af0 : ldr r7, [r6, #96] --+
3231 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3232 * 0x426a9af4 : mov r3, r12 |
3233 * 0x426a9af6 : blx r7 --+
3234 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3235 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3236 * 0x426a9afc : blx_2 see above --+
3237 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3238 * 0x426a9afe (0042): ldr r0, [pc, #52]
3239 * Exception_Handling:
3240 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3241 * 0x426a9b02 (0046): blx r1
3242 * 0x426a9b04 (0048): .align4
3243 * -------- chaining cell (hot): 0x0021
3244 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3245 * 0x426a9b06 (004a): blx r0
3246 * 0x426a9b08 (004c): data 0x7872(30834)
3247 * 0x426a9b0a (004e): data 0x428b(17035)
3248 * 0x426a9b0c (0050): .align4
3249 * -------- chaining cell (predicted)
3250 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3251 * 0x426a9b0e (0052): data 0x0000(0)
3252 * 0x426a9b10 (0054): data 0x0000(0) --> class
3253 * 0x426a9b12 (0056): data 0x0000(0)
3254 * 0x426a9b14 (0058): data 0x0000(0) --> method
3255 * 0x426a9b16 (005a): data 0x0000(0)
3256 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3257 * 0x426a9b1a (005e): data 0x0000(0)
3258 * 0x426a9b28 (006c): .word (0xad0392a5)
3259 * 0x426a9b2c (0070): .word (0x6e750)
3260 * 0x426a9b30 (0074): .word (0x4109a618)
3261 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003262 */
3263 case OP_INVOKE_INTERFACE:
3264 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003265 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003266 int methodIndex = dInsn->vB;
3267
3268 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3269 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3270 else
3271 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3272
Ben Cheng38329f52009-07-07 14:19:20 -07003273 /* "this" is already left in r0 by genProcessArgs* */
3274
3275 /* r4PC = dalvikCallsite */
3276 loadConstant(cUnit, r4PC,
3277 (int) (cUnit->method->insns + mir->offset));
3278
3279 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003280 ArmLIR *addrRetChain =
3281 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003282 addrRetChain->generic.target = (LIR *) retChainingCell;
3283
3284 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003285 ArmLIR *predictedChainingCell =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003286 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003287 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3288
3289 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3290
3291 /* return through lr - jump to the chaining cell */
3292 genUnconditionalBranch(cUnit, predChainingCell);
3293
3294 /*
3295 * null-check on "this" may have been eliminated, but we still need
3296 * a PC-reconstruction label for stack overflow bailout.
3297 */
3298 if (pcrLabel == NULL) {
3299 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003300 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3301 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003302 pcrLabel->operands[0] = dPC;
3303 pcrLabel->operands[1] = mir->offset;
3304 /* Insert the place holder to the growable list */
3305 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3306 }
3307
3308 /* return through lr+2 - punt to the interpreter */
3309 genUnconditionalBranch(cUnit, pcrLabel);
3310
3311 /*
3312 * return through lr+4 - fully resolve the callee method.
3313 * r1 <- count
3314 * r2 <- &predictedChainCell
3315 * r3 <- this->class
3316 * r4 <- dPC
3317 * r7 <- this->class->vtable
3318 */
3319
3320 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003321 opRegReg(cUnit, OP_MOV, r9, r1);
3322 opRegReg(cUnit, OP_MOV, r10, r2);
3323 opRegReg(cUnit, OP_MOV, r12, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003324
Ben Chengba4fc8b2009-06-01 13:00:29 -07003325 /* r0 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003326 opRegReg(cUnit, OP_MOV, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003327
3328 /* r1 = BBBB */
3329 loadConstant(cUnit, r1, dInsn->vB);
3330
3331 /* r2 = method (caller) */
3332 loadConstant(cUnit, r2, (int) cUnit->method);
3333
3334 /* r3 = pDvmDex */
3335 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3336
3337 loadConstant(cUnit, r7,
3338 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003339 opReg(cUnit, OP_BLX, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003340
3341 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3342
Bill Buzbee270c1d62009-08-13 16:58:07 -07003343 opRegReg(cUnit, OP_MOV, r1, r9);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003344
Ben Cheng38329f52009-07-07 14:19:20 -07003345 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003346 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003347
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003348 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003349 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07003350
Bill Buzbee270c1d62009-08-13 16:58:07 -07003351 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3352 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003353
Bill Buzbee270c1d62009-08-13 16:58:07 -07003354 opRegReg(cUnit, OP_MOV, r2, r10);
3355 opRegReg(cUnit, OP_MOV, r3, r12);
Ben Cheng38329f52009-07-07 14:19:20 -07003356
3357 /*
3358 * r0 = calleeMethod
3359 * r2 = &predictedChainingCell
3360 * r3 = class
3361 *
3362 * &returnChainingCell has been loaded into r1 but is not needed
3363 * when patching the chaining cell and will be clobbered upon
3364 * returning so it will be reconstructed again.
3365 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003366 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003367
3368 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003369 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003370 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003371
3372 bypassRechaining->generic.target = (LIR *) addrRetChain;
3373
Ben Chengba4fc8b2009-06-01 13:00:29 -07003374 /*
3375 * r0 = this, r1 = calleeMethod,
3376 * r1 = &ChainingCell,
3377 * r4PC = callsiteDPC,
3378 */
3379 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3380#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003381 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003382#endif
3383 /* Handle exceptions using the interpreter */
3384 genTrap(cUnit, mir->offset, pcrLabel);
3385 break;
3386 }
3387 /* NOP */
3388 case OP_INVOKE_DIRECT_EMPTY: {
3389 return false;
3390 }
3391 case OP_FILLED_NEW_ARRAY:
3392 case OP_FILLED_NEW_ARRAY_RANGE: {
3393 /* Just let the interpreter deal with these */
3394 genInterpSingleStep(cUnit, mir);
3395 break;
3396 }
3397 default:
3398 return true;
3399 }
3400 return false;
3401}
3402
3403static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003404 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003405{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003406 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3407 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3408 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003409
3410 DecodedInstruction *dInsn = &mir->dalvikInsn;
3411 switch (mir->dalvikInsn.opCode) {
3412 /* calleeMethod = this->clazz->vtable[BBBB] */
3413 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3414 case OP_INVOKE_VIRTUAL_QUICK: {
3415 int methodIndex = dInsn->vB;
3416 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3417 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3418 else
3419 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3420
Ben Cheng38329f52009-07-07 14:19:20 -07003421 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3422 retChainingCell,
3423 predChainingCell,
3424 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003425 break;
3426 }
3427 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3428 case OP_INVOKE_SUPER_QUICK:
3429 case OP_INVOKE_SUPER_QUICK_RANGE: {
3430 const Method *calleeMethod =
3431 cUnit->method->clazz->super->vtable[dInsn->vB];
3432
3433 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3434 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3435 else
3436 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3437
3438 /* r0 = calleeMethod */
3439 loadConstant(cUnit, r0, (int) calleeMethod);
3440
Ben Cheng38329f52009-07-07 14:19:20 -07003441 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3442 calleeMethod);
3443 /* Handle exceptions using the interpreter */
3444 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003445 break;
3446 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003447 default:
3448 return true;
3449 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003450 return false;
3451}
3452
3453/*
3454 * NOTE: We assume here that the special native inline routines
3455 * are side-effect free. By making this assumption, we can safely
3456 * re-execute the routine from the interpreter if it decides it
3457 * wants to throw an exception. We still need to EXPORT_PC(), though.
3458 */
3459static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3460{
3461 DecodedInstruction *dInsn = &mir->dalvikInsn;
3462 switch( mir->dalvikInsn.opCode) {
3463 case OP_EXECUTE_INLINE: {
3464 unsigned int i;
3465 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003466 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003467 int operation = dInsn->vB;
3468
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003469 switch (operation) {
3470 case INLINE_EMPTYINLINEMETHOD:
3471 return false; /* Nop */
3472 case INLINE_STRING_LENGTH:
3473 return genInlinedStringLength(cUnit, mir);
3474 case INLINE_MATH_ABS_INT:
3475 return genInlinedAbsInt(cUnit, mir);
3476 case INLINE_MATH_ABS_LONG:
3477 return genInlinedAbsLong(cUnit, mir);
3478 case INLINE_MATH_MIN_INT:
3479 return genInlinedMinMaxInt(cUnit, mir, true);
3480 case INLINE_MATH_MAX_INT:
3481 return genInlinedMinMaxInt(cUnit, mir, false);
3482 case INLINE_STRING_CHARAT:
3483 return genInlinedStringCharAt(cUnit, mir);
3484 case INLINE_MATH_SQRT:
3485 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003486 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003487 else
3488 break; /* Handle with C routine */
3489 case INLINE_MATH_COS:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003490 case INLINE_MATH_SIN:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003491 break; /* Handle with C routine */
3492 case INLINE_MATH_ABS_FLOAT:
3493 return genInlinedAbsFloat(cUnit, mir);
3494 case INLINE_MATH_ABS_DOUBLE:
3495 return genInlinedAbsDouble(cUnit, mir);
3496 case INLINE_STRING_COMPARETO:
3497 case INLINE_STRING_EQUALS:
Bill Buzbee12ba0152009-09-03 14:03:09 -07003498 case INLINE_STRING_INDEXOF_I:
3499 case INLINE_STRING_INDEXOF_II:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003500 break;
3501 default:
3502 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003503 }
3504
3505 /* Materialize pointer to retval & push */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003506 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3507 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3508
Ben Chengba4fc8b2009-06-01 13:00:29 -07003509 /* Push r4 and (just to take up space) r5) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003510 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003511
3512 /* Get code pointer to inline routine */
3513 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3514
3515 /* Export PC */
3516 genExportPC(cUnit, mir, r0, r1 );
3517
3518 /* Load arguments to r0 through r3 as applicable */
3519 for (i=0; i < dInsn->vA; i++) {
3520 loadValue(cUnit, dInsn->arg[i], i);
3521 }
3522 /* Call inline routine */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003523 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003524
3525 /* Strip frame */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003526 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003527
3528 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003529 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003530
Ben Chenge9695e52009-06-16 16:11:47 -07003531 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003532 break;
3533 }
3534 default:
3535 return true;
3536 }
3537 return false;
3538}
3539
3540static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3541{
3542 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3543 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3544 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3545 return false;
3546}
3547
Ben Chengba4fc8b2009-06-01 13:00:29 -07003548/*
3549 * The following are special processing routines that handle transfer of
3550 * controls between compiled code and the interpreter. Certain VM states like
3551 * Dalvik PC and special-purpose registers are reconstructed here.
3552 */
3553
Ben Cheng1efc9c52009-06-08 18:25:27 -07003554/* Chaining cell for code that may need warmup. */
3555static void handleNormalChainingCell(CompilationUnit *cUnit,
3556 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003557{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003558 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3559 jitToInterpEntries.dvmJitToInterpNormal), r0);
3560 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003561 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3562}
3563
3564/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003565 * Chaining cell for instructions that immediately following already translated
3566 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003567 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003568static void handleHotChainingCell(CompilationUnit *cUnit,
3569 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003570{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003571 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3572 jitToInterpEntries.dvmJitToTraceSelect), r0);
3573 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003574 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3575}
3576
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003577#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003578/* Chaining cell for branches that branch back into the same basic block */
3579static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3580 unsigned int offset)
3581{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003582#if defined(WITH_SELF_VERIFICATION)
Jeff Hao97319a82009-08-12 16:57:15 -07003583 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3584 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003585#else
3586 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3587 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3588#endif
Jeff Hao97319a82009-08-12 16:57:15 -07003589 newLIR1(cUnit, THUMB_BLX_R, r0);
3590 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3591}
3592
3593#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003594/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003595static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3596 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003597{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003598 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3599 jitToInterpEntries.dvmJitToTraceSelect), r0);
3600 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003601 addWordData(cUnit, (int) (callee->insns), true);
3602}
3603
Ben Cheng38329f52009-07-07 14:19:20 -07003604/* Chaining cell for monomorphic method invocations. */
3605static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3606{
3607
3608 /* Should not be executed in the initial state */
3609 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3610 /* To be filled: class */
3611 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3612 /* To be filled: method */
3613 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3614 /*
3615 * Rechain count. The initial value of 0 here will trigger chaining upon
3616 * the first invocation of this callsite.
3617 */
3618 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3619}
3620
Ben Chengba4fc8b2009-06-01 13:00:29 -07003621/* Load the Dalvik PC into r0 and jump to the specified target */
3622static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003623 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003624{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003625 ArmLIR **pcrLabel =
3626 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003627 int numElems = cUnit->pcReconstructionList.numUsed;
3628 int i;
3629 for (i = 0; i < numElems; i++) {
3630 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3631 /* r0 = dalvik PC */
3632 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3633 genUnconditionalBranch(cUnit, targetLabel);
3634 }
3635}
3636
Ben Cheng4238ec22009-08-24 16:32:22 -07003637static char *extendedMIROpNames[MIR_OP_LAST - MIR_OP_FIRST] = {
3638 "MIR_OP_PHI",
3639 "MIR_OP_NULL_N_RANGE_UP_CHECK",
3640 "MIR_OP_NULL_N_RANGE_DOWN_CHECK",
3641 "MIR_OP_LOWER_BOUND_CHECK",
3642 "MIR_OP_PUNT",
3643};
3644
3645/*
3646 * vA = arrayReg;
3647 * vB = idxReg;
3648 * vC = endConditionReg;
3649 * arg[0] = maxC
3650 * arg[1] = minC
3651 * arg[2] = loopBranchConditionCode
3652 */
3653static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3654{
3655 DecodedInstruction *dInsn = &mir->dalvikInsn;
3656 const int lenOffset = offsetof(ArrayObject, length);
3657 const int regArray = 0;
3658 const int regIdxEnd = NEXT_REG(regArray);
3659 const int regLength = regArray;
3660 const int maxC = dInsn->arg[0];
3661 const int minC = dInsn->arg[1];
3662
3663 /* regArray <- arrayRef */
3664 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3665 loadValue(cUnit, mir->dalvikInsn.vC, regIdxEnd);
3666 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3667 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3668
3669 /* regLength <- len(arrayRef) */
3670 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3671
3672 int delta = maxC;
3673 /*
3674 * If the loop end condition is ">=" instead of ">", then the largest value
3675 * of the index is "endCondition - 1".
3676 */
3677 if (dInsn->arg[2] == OP_IF_GE) {
3678 delta--;
3679 }
3680
3681 if (delta) {
3682 opRegImm(cUnit, OP_ADD, regIdxEnd, delta, regIdxEnd);
3683 }
3684 /* Punt if "regIdxEnd < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003685 genRegRegCheck(cUnit, ARM_COND_GE, regIdxEnd, regLength, 0,
3686 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003687}
3688
3689/*
3690 * vA = arrayReg;
3691 * vB = idxReg;
3692 * vC = endConditionReg;
3693 * arg[0] = maxC
3694 * arg[1] = minC
3695 * arg[2] = loopBranchConditionCode
3696 */
3697static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3698{
3699 DecodedInstruction *dInsn = &mir->dalvikInsn;
3700 const int lenOffset = offsetof(ArrayObject, length);
3701 const int regArray = 0;
3702 const int regIdxInit = NEXT_REG(regArray);
3703 const int regLength = regArray;
3704 const int maxC = dInsn->arg[0];
3705 const int minC = dInsn->arg[1];
3706
3707 /* regArray <- arrayRef */
3708 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3709 loadValue(cUnit, mir->dalvikInsn.vB, regIdxInit);
3710 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3711 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3712
3713 /* regLength <- len(arrayRef) */
3714 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3715
3716 if (maxC) {
3717 opRegImm(cUnit, OP_ADD, regIdxInit, maxC, regIdxInit);
3718 }
3719
3720 /* Punt if "regIdxInit < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003721 genRegRegCheck(cUnit, ARM_COND_GE, regIdxInit, regLength, 0,
3722 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003723}
3724
3725/*
3726 * vA = idxReg;
3727 * vB = minC;
3728 */
3729static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3730{
3731 DecodedInstruction *dInsn = &mir->dalvikInsn;
3732 const int regIdx = 0;
3733 const int minC = dInsn->vB;
3734
3735 /* regIdx <- initial index value */
3736 loadValue(cUnit, mir->dalvikInsn.vA, regIdx);
3737
3738 /* Punt if "regIdxInit + minC >= 0" is false */
3739 genRegImmCheck(cUnit, ARM_COND_LT, regIdx, -minC, 0,
3740 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3741}
3742
3743/* Extended MIR instructions like PHI */
3744static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3745{
3746 int opOffset = mir->dalvikInsn.opCode - MIR_OP_FIRST;
3747 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3748 false);
3749 strcpy(msg, extendedMIROpNames[opOffset]);
3750 newLIR1(cUnit, ARM_PSEUDO_EXTENDED_MIR, (int) msg);
3751
3752 switch (mir->dalvikInsn.opCode) {
3753 case MIR_OP_PHI: {
3754 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3755 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3756 break;
3757 }
3758 case MIR_OP_NULL_N_RANGE_UP_CHECK: {
3759 genHoistedChecksForCountUpLoop(cUnit, mir);
3760 break;
3761 }
3762 case MIR_OP_NULL_N_RANGE_DOWN_CHECK: {
3763 genHoistedChecksForCountDownLoop(cUnit, mir);
3764 break;
3765 }
3766 case MIR_OP_LOWER_BOUND_CHECK: {
3767 genHoistedLowerBoundCheck(cUnit, mir);
3768 break;
3769 }
3770 case MIR_OP_PUNT: {
3771 genUnconditionalBranch(cUnit,
3772 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3773 break;
3774 }
3775 default:
3776 break;
3777 }
3778}
3779
3780/*
3781 * Create a PC-reconstruction cell for the starting offset of this trace.
3782 * Since the PCR cell is placed near the end of the compiled code which is
3783 * usually out of range for a conditional branch, we put two branches (one
3784 * branch over to the loop body and one layover branch to the actual PCR) at the
3785 * end of the entry block.
3786 */
3787static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3788 ArmLIR *bodyLabel)
3789{
3790 /* Set up the place holder to reconstruct this Dalvik PC */
3791 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3792 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
3793 pcrLabel->operands[0] =
3794 (int) (cUnit->method->insns + entry->startOffset);
3795 pcrLabel->operands[1] = entry->startOffset;
3796 /* Insert the place holder to the growable list */
3797 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3798
3799 /*
3800 * Next, create two branches - one branch over to the loop body and the
3801 * other branch to the PCR cell to punt.
3802 */
3803 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3804 branchToBody->opCode = THUMB_B_UNCOND;
3805 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003806 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07003807 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3808
3809 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3810 branchToPCR->opCode = THUMB_B_UNCOND;
3811 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003812 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003813 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3814}
3815
Ben Chengba4fc8b2009-06-01 13:00:29 -07003816void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3817{
3818 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003819 ArmLIR *labelList =
3820 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003821 GrowableList chainingListByType[CHAINING_CELL_LAST];
3822 int i;
3823
3824 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003825 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003826 */
3827 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3828 dvmInitGrowableList(&chainingListByType[i], 2);
3829 }
3830
3831 BasicBlock **blockList = cUnit->blockList;
3832
Bill Buzbee6e963e12009-06-17 16:56:19 -07003833 if (cUnit->executionCount) {
3834 /*
3835 * Reserve 6 bytes at the beginning of the trace
3836 * +----------------------------+
3837 * | execution count (4 bytes) |
3838 * +----------------------------+
3839 * | chain cell offset (2 bytes)|
3840 * +----------------------------+
3841 * ...and then code to increment the execution
3842 * count:
3843 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3844 * sub r0, #10 @ back up to addr of executionCount
3845 * ldr r1, [r0]
3846 * add r1, #1
3847 * str r1, [r0]
3848 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003849 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3850 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003851 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003852 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003853 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003854 /* Thumb instruction used directly here to ensure correct size */
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003855 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003856 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3857 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3858 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3859 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003860 } else {
3861 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003862 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003863 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003864 cUnit->headerSize = 2;
3865 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003866
Ben Chengba4fc8b2009-06-01 13:00:29 -07003867 /* Handle the content in each basic block */
3868 for (i = 0; i < cUnit->numBlocks; i++) {
3869 blockList[i]->visited = true;
3870 MIR *mir;
3871
3872 labelList[i].operands[0] = blockList[i]->startOffset;
3873
3874 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3875 /*
3876 * Append the label pseudo LIR first. Chaining cells will be handled
3877 * separately afterwards.
3878 */
3879 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3880 }
3881
Ben Cheng4238ec22009-08-24 16:32:22 -07003882 if (blockList[i]->blockType == ENTRY_BLOCK) {
3883 labelList[i].opCode = ARM_PSEUDO_ENTRY_BLOCK;
3884 if (blockList[i]->firstMIRInsn == NULL) {
3885 continue;
3886 } else {
3887 setupLoopEntryBlock(cUnit, blockList[i],
3888 &labelList[blockList[i]->fallThrough->id]);
3889 }
3890 } else if (blockList[i]->blockType == EXIT_BLOCK) {
3891 labelList[i].opCode = ARM_PSEUDO_EXIT_BLOCK;
3892 goto gen_fallthrough;
3893 } else if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003894 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003895 /* Reset the register state */
3896 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003897 } else {
3898 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003899 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003900 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003901 /* handle the codegen later */
3902 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003903 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003904 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003905 case CHAINING_CELL_INVOKE_SINGLETON:
3906 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003907 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003908 labelList[i].operands[0] =
3909 (int) blockList[i]->containingMethod;
3910 /* handle the codegen later */
3911 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003912 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3913 (void *) i);
3914 break;
3915 case CHAINING_CELL_INVOKE_PREDICTED:
3916 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003917 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003918 /* handle the codegen later */
3919 dvmInsertGrowableList(
3920 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3921 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003922 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003923 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003924 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003925 ARM_PSEUDO_CHAINING_CELL_HOT;
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_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003929 (void *) i);
3930 break;
3931 case PC_RECONSTRUCTION:
3932 /* Make sure exception handling block is next */
3933 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003934 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003935 assert (i == cUnit->numBlocks - 2);
3936 handlePCReconstruction(cUnit, &labelList[i+1]);
3937 break;
3938 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003939 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003940 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003941 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3942 jitToInterpEntries.dvmJitToInterpPunt),
3943 r1);
3944 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003945 }
3946 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003947#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003948 case CHAINING_CELL_BACKWARD_BRANCH:
3949 labelList[i].opCode =
3950 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3951 /* handle the codegen later */
3952 dvmInsertGrowableList(
3953 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3954 (void *) i);
3955 break;
3956#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003957 default:
3958 break;
3959 }
3960 continue;
3961 }
Ben Chenge9695e52009-06-16 16:11:47 -07003962
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003963 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003964
Ben Chengba4fc8b2009-06-01 13:00:29 -07003965 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003966 if (mir->dalvikInsn.opCode >= MIR_OP_FIRST) {
3967 handleExtendedMIR(cUnit, mir);
3968 continue;
3969 }
3970
Ben Chengba4fc8b2009-06-01 13:00:29 -07003971 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3972 InstructionFormat dalvikFormat =
3973 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003974 ArmLIR *boundaryLIR =
3975 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Cheng4238ec22009-08-24 16:32:22 -07003976 mir->offset, dalvikOpCode);
3977 if (mir->ssaRep) {
3978 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3979 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3980 }
3981
Ben Chenge9695e52009-06-16 16:11:47 -07003982 /* Remember the first LIR for this block */
3983 if (headLIR == NULL) {
3984 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07003985 /* Set the first boundaryLIR as a scheduling barrier */
3986 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07003987 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003988
Ben Chengba4fc8b2009-06-01 13:00:29 -07003989 bool notHandled;
3990 /*
3991 * Debugging: screen the opcode first to see if it is in the
3992 * do[-not]-compile list
3993 */
3994 bool singleStepMe =
3995 gDvmJit.includeSelectedOp !=
3996 ((gDvmJit.opList[dalvikOpCode >> 3] &
3997 (1 << (dalvikOpCode & 0x7))) !=
3998 0);
Jeff Hao97319a82009-08-12 16:57:15 -07003999#if defined(WITH_SELF_VERIFICATION)
4000 /* Punt on opcodes we can't replay */
4001 if (selfVerificationPuntOps(dalvikOpCode))
4002 singleStepMe = true;
4003#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004004 if (singleStepMe || cUnit->allSingleStep) {
4005 notHandled = false;
4006 genInterpSingleStep(cUnit, mir);
4007 } else {
4008 opcodeCoverage[dalvikOpCode]++;
4009 switch (dalvikFormat) {
4010 case kFmt10t:
4011 case kFmt20t:
4012 case kFmt30t:
4013 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4014 mir, blockList[i], labelList);
4015 break;
4016 case kFmt10x:
4017 notHandled = handleFmt10x(cUnit, mir);
4018 break;
4019 case kFmt11n:
4020 case kFmt31i:
4021 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4022 break;
4023 case kFmt11x:
4024 notHandled = handleFmt11x(cUnit, mir);
4025 break;
4026 case kFmt12x:
4027 notHandled = handleFmt12x(cUnit, mir);
4028 break;
4029 case kFmt20bc:
4030 notHandled = handleFmt20bc(cUnit, mir);
4031 break;
4032 case kFmt21c:
4033 case kFmt31c:
4034 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4035 break;
4036 case kFmt21h:
4037 notHandled = handleFmt21h(cUnit, mir);
4038 break;
4039 case kFmt21s:
4040 notHandled = handleFmt21s(cUnit, mir);
4041 break;
4042 case kFmt21t:
4043 notHandled = handleFmt21t(cUnit, mir, blockList[i],
4044 labelList);
4045 break;
4046 case kFmt22b:
4047 case kFmt22s:
4048 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4049 break;
4050 case kFmt22c:
4051 notHandled = handleFmt22c(cUnit, mir);
4052 break;
4053 case kFmt22cs:
4054 notHandled = handleFmt22cs(cUnit, mir);
4055 break;
4056 case kFmt22t:
4057 notHandled = handleFmt22t(cUnit, mir, blockList[i],
4058 labelList);
4059 break;
4060 case kFmt22x:
4061 case kFmt32x:
4062 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4063 break;
4064 case kFmt23x:
4065 notHandled = handleFmt23x(cUnit, mir);
4066 break;
4067 case kFmt31t:
4068 notHandled = handleFmt31t(cUnit, mir);
4069 break;
4070 case kFmt3rc:
4071 case kFmt35c:
4072 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4073 labelList);
4074 break;
4075 case kFmt3rms:
4076 case kFmt35ms:
4077 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4078 labelList);
4079 break;
4080 case kFmt3inline:
4081 notHandled = handleFmt3inline(cUnit, mir);
4082 break;
4083 case kFmt51l:
4084 notHandled = handleFmt51l(cUnit, mir);
4085 break;
4086 default:
4087 notHandled = true;
4088 break;
4089 }
4090 }
4091 if (notHandled) {
4092 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4093 mir->offset,
4094 dalvikOpCode, getOpcodeName(dalvikOpCode),
4095 dalvikFormat);
4096 dvmAbort();
4097 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004098 }
4099 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004100
4101 if (blockList[i]->blockType == ENTRY_BLOCK) {
4102 dvmCompilerAppendLIR(cUnit,
4103 (LIR *) cUnit->loopAnalysis->branchToBody);
4104 dvmCompilerAppendLIR(cUnit,
4105 (LIR *) cUnit->loopAnalysis->branchToPCR);
4106 }
4107
4108 if (headLIR) {
4109 /*
4110 * Eliminate redundant loads/stores and delay stores into later
4111 * slots
4112 */
4113 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4114 cUnit->lastLIRInsn);
4115 }
4116
4117gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004118 /*
4119 * Check if the block is terminated due to trace length constraint -
4120 * insert an unconditional branch to the chaining cell.
4121 */
4122 if (blockList[i]->needFallThroughBranch) {
4123 genUnconditionalBranch(cUnit,
4124 &labelList[blockList[i]->fallThrough->id]);
4125 }
4126
Ben Chengba4fc8b2009-06-01 13:00:29 -07004127 }
4128
Ben Chenge9695e52009-06-16 16:11:47 -07004129 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07004130 for (i = 0; i < CHAINING_CELL_LAST; i++) {
4131 size_t j;
4132 int *blockIdList = (int *) chainingListByType[i].elemList;
4133
4134 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4135
4136 /* No chaining cells of this type */
4137 if (cUnit->numChainingCells[i] == 0)
4138 continue;
4139
4140 /* Record the first LIR for a new type of chaining cell */
4141 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4142
4143 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4144 int blockId = blockIdList[j];
4145
4146 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004147 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004148
4149 /* Insert the pseudo chaining instruction */
4150 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4151
4152
4153 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07004154 case CHAINING_CELL_NORMAL:
4155 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004156 blockList[blockId]->startOffset);
4157 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004158 case CHAINING_CELL_INVOKE_SINGLETON:
4159 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004160 blockList[blockId]->containingMethod);
4161 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004162 case CHAINING_CELL_INVOKE_PREDICTED:
4163 handleInvokePredictedChainingCell(cUnit);
4164 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07004165 case CHAINING_CELL_HOT:
4166 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004167 blockList[blockId]->startOffset);
4168 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004169#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07004170 case CHAINING_CELL_BACKWARD_BRANCH:
4171 handleBackwardBranchChainingCell(cUnit,
4172 blockList[blockId]->startOffset);
4173 break;
4174#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004175 default:
4176 dvmAbort();
4177 break;
4178 }
4179 }
4180 }
Ben Chenge9695e52009-06-16 16:11:47 -07004181
4182 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004183}
4184
4185/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004186bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004187{
Bill Buzbee716f1202009-07-23 13:22:09 -07004188 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004189
4190 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07004191 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004192 }
4193
4194 switch (work->kind) {
4195 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07004196 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004197 break;
4198 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004199 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07004200 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004201 break;
4202 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07004203 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004204 dvmAbort();
4205 }
4206 return res;
4207}
4208
Ben Chengba4fc8b2009-06-01 13:00:29 -07004209/* Architectural-specific debugging helpers go here */
4210void dvmCompilerArchDump(void)
4211{
4212 /* Print compiled opcode in this VM instance */
4213 int i, start, streak;
4214 char buf[1024];
4215
4216 streak = i = 0;
4217 buf[0] = 0;
4218 while (opcodeCoverage[i] == 0 && i < 256) {
4219 i++;
4220 }
4221 if (i == 256) {
4222 return;
4223 }
4224 for (start = i++, streak = 1; i < 256; i++) {
4225 if (opcodeCoverage[i]) {
4226 streak++;
4227 } else {
4228 if (streak == 1) {
4229 sprintf(buf+strlen(buf), "%x,", start);
4230 } else {
4231 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4232 }
4233 streak = 0;
4234 while (opcodeCoverage[i] == 0 && i < 256) {
4235 i++;
4236 }
4237 if (i < 256) {
4238 streak = 1;
4239 start = i;
4240 }
4241 }
4242 }
4243 if (streak) {
4244 if (streak == 1) {
4245 sprintf(buf+strlen(buf), "%x", start);
4246 } else {
4247 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4248 }
4249 }
4250 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004251 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004252 }
4253}
Ben Chengd7d426a2009-09-22 11:23:36 -07004254
4255/* Common initialization routine for an architecture family */
4256bool dvmCompilerArchInit()
4257{
4258 int i;
4259
4260 for (i = 0; i < ARM_LAST; i++) {
4261 if (EncodingMap[i].opCode != i) {
4262 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4263 EncodingMap[i].name, i, EncodingMap[i].opCode);
4264 dvmAbort();
4265 }
4266 }
4267
4268 return compilerArchVariantInit();
4269}