blob: 65792bea8843d715e786a57b56bd38f673887901 [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 Chenge9695e52009-06-16 16:11:47 -0700997 reg0 = selectFirstRegister(cUnit, vArray, false);
998 reg1 = NEXT_REG(reg0);
999 reg2 = NEXT_REG(reg1);
1000 reg3 = NEXT_REG(reg2);
1001
1002 loadValue(cUnit, vArray, reg2);
1003 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001004
1005 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001006 ArmLIR * pcrLabel = NULL;
1007
1008 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
1009 pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
1010 }
1011
1012 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1013 /* Get len */
1014 loadWordDisp(cUnit, reg2, lenOffset, reg0);
1015 /* reg2 -> array data */
1016 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1017 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
1018 } else {
1019 /* reg2 -> array data */
1020 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1021 }
Jeff Hao97319a82009-08-12 16:57:15 -07001022#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001023 if ((size == LONG) || (size == DOUBLE)) {
1024 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
1025 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1026 loadBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
1027 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
1028 loadBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
Ben Chenge9695e52009-06-16 16:11:47 -07001029 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001030 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001031 loadBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
Ben Chenge9695e52009-06-16 16:11:47 -07001032 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001033 }
Jeff Hao97319a82009-08-12 16:57:15 -07001034#else
Bill Buzbee270c1d62009-08-13 16:58:07 -07001035 //TODO: probably want to move this into loadBaseIndexed
1036 void *funct = NULL;
1037 switch(size) {
1038 case LONG:
1039 case DOUBLE:
Jeff Hao97319a82009-08-12 16:57:15 -07001040 funct = (void*) &selfVerificationLoadDoubleword;
1041 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001042 case WORD:
Jeff Hao97319a82009-08-12 16:57:15 -07001043 funct = (void*) &selfVerificationLoad;
1044 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001045 case UNSIGNED_HALF:
1046 funct = (void*) &selfVerificationLoadHalfword;
1047 break;
1048 case SIGNED_HALF:
1049 funct = (void*) &selfVerificationLoadSignedHalfword;
1050 break;
1051 case UNSIGNED_BYTE:
1052 funct = (void*) &selfVerificationLoadByte;
1053 break;
1054 case SIGNED_BYTE:
1055 funct = (void*) &selfVerificationLoadSignedByte;
1056 break;
1057 default:
1058 assert(0);
1059 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -07001060 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001061 /* Combine address and index */
1062 if (scale)
1063 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1064 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001065
1066 int regMap = reg1 << 8 | reg0 << 4 | reg2;
1067 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1068
Bill Buzbee270c1d62009-08-13 16:58:07 -07001069 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001070
Bill Buzbee270c1d62009-08-13 16:58:07 -07001071 if ((size == LONG) || (size == DOUBLE))
Jeff Hao97319a82009-08-12 16:57:15 -07001072 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
1073 else
1074 storeValue(cUnit, reg0, vDest, reg3);
1075#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001076}
1077
Ben Chengba4fc8b2009-06-01 13:00:29 -07001078/*
1079 * Generate array store
1080 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001081 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001082static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001083 int vArray, int vIndex, int vSrc, int scale)
1084{
1085 int lenOffset = offsetof(ArrayObject, length);
1086 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -07001087 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001088
Ben Chenge9695e52009-06-16 16:11:47 -07001089 reg0 = selectFirstRegister(cUnit, vArray, false);
1090 reg1 = NEXT_REG(reg0);
1091 reg2 = NEXT_REG(reg1);
1092 reg3 = NEXT_REG(reg2);
1093
1094 loadValue(cUnit, vArray, reg2);
1095 loadValue(cUnit, vIndex, reg3);
1096
Ben Cheng1efc9c52009-06-08 18:25:27 -07001097 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001098 ArmLIR * pcrLabel = NULL;
1099
1100 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
1101 pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
1102 }
1103
1104 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1105 /* Get len */
1106 loadWordDisp(cUnit, reg2, lenOffset, reg0);
1107 /* reg2 -> array data */
1108 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1109 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
1110 } else {
1111 /* reg2 -> array data */
1112 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1113 }
1114
Ben Chenge9695e52009-06-16 16:11:47 -07001115 /* at this point, reg2 points to array, reg3 is unscaled index */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001116#if !defined(WITH_SELF_VERIFICATION)
1117 if ((size == LONG) || (size == DOUBLE)) {
1118 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
1119 loadValuePair(cUnit, vSrc, reg0, reg1);
1120 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
1121 if (scale)
1122 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1123 storeBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
1124 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
1125 storeBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
1126 } else {
1127 loadValue(cUnit, vSrc, reg0);
1128 updateLiveRegister(cUnit, vSrc, reg0);
1129 storeBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
1130 }
1131#else
1132 //TODO: probably want to move this into storeBaseIndexed
1133 void *funct = NULL;
1134 switch(size) {
1135 case LONG:
1136 case DOUBLE:
1137 funct = (void*) &selfVerificationStoreDoubleword;
1138 break;
1139 case WORD:
1140 funct = (void*) &selfVerificationStore;
1141 break;
1142 case SIGNED_HALF:
1143 case UNSIGNED_HALF:
1144 funct = (void*) &selfVerificationStoreHalfword;
1145 break;
1146 case SIGNED_BYTE:
1147 case UNSIGNED_BYTE:
1148 funct = (void*) &selfVerificationStoreByte;
1149 break;
1150 default:
1151 assert(0);
1152 dvmAbort();
1153 }
1154
1155 /* Combine address and index */
1156 if ((size == LONG) || (size == DOUBLE)) {
Ben Chenge9695e52009-06-16 16:11:47 -07001157 loadValuePair(cUnit, vSrc, reg0, reg1);
1158 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001159 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001160 loadValue(cUnit, vSrc, reg0);
1161 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001162 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001163 if (scale)
1164 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1165 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001166
1167 int regMap = reg1 << 8 | reg0 << 4 | reg2;
1168 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1169
Bill Buzbee270c1d62009-08-13 16:58:07 -07001170 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001171#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001172}
1173
1174static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1175 int vSrc1, int vShift)
1176{
Ben Chenge9695e52009-06-16 16:11:47 -07001177 /*
1178 * Don't mess with the regsiters here as there is a particular calling
1179 * convention to the out-of-line handler.
1180 */
1181 loadValue(cUnit, vShift, r2);
1182 loadValuePair(cUnit, vSrc1, r0, r1);
1183 switch( mir->dalvikInsn.opCode) {
1184 case OP_SHL_LONG:
1185 case OP_SHL_LONG_2ADDR:
1186 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1187 break;
1188 case OP_SHR_LONG:
1189 case OP_SHR_LONG_2ADDR:
1190 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1191 break;
1192 case OP_USHR_LONG:
1193 case OP_USHR_LONG_2ADDR:
1194 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1195 break;
1196 default:
1197 return true;
1198 }
1199 storeValuePair(cUnit, r0, r1, vDest, r2);
1200 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001201}
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001202bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1203 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001204{
Ben Chenge9695e52009-06-16 16:11:47 -07001205 /*
1206 * Don't optimize the regsiter usage here as they are governed by the EABI
1207 * calling convention.
1208 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001209 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001210 int reg0, reg1;
1211
Ben Chengba4fc8b2009-06-01 13:00:29 -07001212 /* TODO: use a proper include file to define these */
1213 float __aeabi_fadd(float a, float b);
1214 float __aeabi_fsub(float a, float b);
1215 float __aeabi_fdiv(float a, float b);
1216 float __aeabi_fmul(float a, float b);
1217 float fmodf(float a, float b);
1218
Ben Chenge9695e52009-06-16 16:11:47 -07001219 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1220 reg1 = NEXT_REG(reg0);
1221
Ben Chengba4fc8b2009-06-01 13:00:29 -07001222 switch (mir->dalvikInsn.opCode) {
1223 case OP_ADD_FLOAT_2ADDR:
1224 case OP_ADD_FLOAT:
1225 funct = (void*) __aeabi_fadd;
1226 break;
1227 case OP_SUB_FLOAT_2ADDR:
1228 case OP_SUB_FLOAT:
1229 funct = (void*) __aeabi_fsub;
1230 break;
1231 case OP_DIV_FLOAT_2ADDR:
1232 case OP_DIV_FLOAT:
1233 funct = (void*) __aeabi_fdiv;
1234 break;
1235 case OP_MUL_FLOAT_2ADDR:
1236 case OP_MUL_FLOAT:
1237 funct = (void*) __aeabi_fmul;
1238 break;
1239 case OP_REM_FLOAT_2ADDR:
1240 case OP_REM_FLOAT:
1241 funct = (void*) fmodf;
1242 break;
1243 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -07001244 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001245 opRegImm(cUnit, OP_ADD, reg0, 0x80000000, reg1);
Ben Chenge9695e52009-06-16 16:11:47 -07001246 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001247 return false;
1248 }
1249 default:
1250 return true;
1251 }
1252 loadConstant(cUnit, r2, (int)funct);
1253 loadValue(cUnit, vSrc1, r0);
1254 loadValue(cUnit, vSrc2, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001255 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001256 storeValue(cUnit, r0, vDest, r1);
1257 return false;
1258}
1259
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001260bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1261 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001262{
1263 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001264 int reg0, reg1, reg2;
1265
Ben Chengba4fc8b2009-06-01 13:00:29 -07001266 /* TODO: use a proper include file to define these */
1267 double __aeabi_dadd(double a, double b);
1268 double __aeabi_dsub(double a, double b);
1269 double __aeabi_ddiv(double a, double b);
1270 double __aeabi_dmul(double a, double b);
1271 double fmod(double a, double b);
1272
Ben Chenge9695e52009-06-16 16:11:47 -07001273 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1274 reg1 = NEXT_REG(reg0);
1275 reg2 = NEXT_REG(reg1);
1276
Ben Chengba4fc8b2009-06-01 13:00:29 -07001277 switch (mir->dalvikInsn.opCode) {
1278 case OP_ADD_DOUBLE_2ADDR:
1279 case OP_ADD_DOUBLE:
1280 funct = (void*) __aeabi_dadd;
1281 break;
1282 case OP_SUB_DOUBLE_2ADDR:
1283 case OP_SUB_DOUBLE:
1284 funct = (void*) __aeabi_dsub;
1285 break;
1286 case OP_DIV_DOUBLE_2ADDR:
1287 case OP_DIV_DOUBLE:
1288 funct = (void*) __aeabi_ddiv;
1289 break;
1290 case OP_MUL_DOUBLE_2ADDR:
1291 case OP_MUL_DOUBLE:
1292 funct = (void*) __aeabi_dmul;
1293 break;
1294 case OP_REM_DOUBLE_2ADDR:
1295 case OP_REM_DOUBLE:
1296 funct = (void*) fmod;
1297 break;
1298 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001299 loadValuePair(cUnit, vSrc2, reg0, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001300 opRegImm(cUnit, OP_ADD, reg1, 0x80000000, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001301 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001302 return false;
1303 }
1304 default:
1305 return true;
1306 }
Ben Chenge9695e52009-06-16 16:11:47 -07001307 /*
1308 * Don't optimize the regsiter usage here as they are governed by the EABI
1309 * calling convention.
1310 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001311 loadConstant(cUnit, r4PC, (int)funct);
1312 loadValuePair(cUnit, vSrc1, r0, r1);
1313 loadValuePair(cUnit, vSrc2, r2, r3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001314 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001315 storeValuePair(cUnit, r0, r1, vDest, r2);
1316 return false;
1317}
1318
1319static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1320 int vSrc1, int vSrc2)
1321{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001322 OpKind firstOp = OP_BKPT;
1323 OpKind secondOp = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001324 bool callOut = false;
1325 void *callTgt;
1326 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -07001327 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001328 /* TODO - find proper .h file to declare these */
1329 long long __aeabi_ldivmod(long long op1, long long op2);
1330
1331 switch (mir->dalvikInsn.opCode) {
1332 case OP_NOT_LONG:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001333 firstOp = OP_MVN;
1334 secondOp = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001335 break;
1336 case OP_ADD_LONG:
1337 case OP_ADD_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001338 firstOp = OP_ADD;
1339 secondOp = OP_ADC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001340 break;
1341 case OP_SUB_LONG:
1342 case OP_SUB_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001343 firstOp = OP_SUB;
1344 secondOp = OP_SBC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001345 break;
1346 case OP_MUL_LONG:
1347 case OP_MUL_LONG_2ADDR:
1348 loadValuePair(cUnit, vSrc1, r0, r1);
1349 loadValuePair(cUnit, vSrc2, r2, r3);
1350 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
1351 storeValuePair(cUnit, r0, r1, vDest, r2);
1352 return false;
1353 break;
1354 case OP_DIV_LONG:
1355 case OP_DIV_LONG_2ADDR:
1356 callOut = true;
1357 retReg = r0;
1358 callTgt = (void*)__aeabi_ldivmod;
1359 break;
1360 /* NOTE - result is in r2/r3 instead of r0/r1 */
1361 case OP_REM_LONG:
1362 case OP_REM_LONG_2ADDR:
1363 callOut = true;
1364 callTgt = (void*)__aeabi_ldivmod;
1365 retReg = r2;
1366 break;
1367 case OP_AND_LONG:
1368 case OP_AND_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001369 firstOp = OP_AND;
1370 secondOp = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001371 break;
1372 case OP_OR_LONG:
1373 case OP_OR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001374 firstOp = OP_OR;
1375 secondOp = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001376 break;
1377 case OP_XOR_LONG:
1378 case OP_XOR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001379 firstOp = OP_XOR;
1380 secondOp = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001381 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001382 case OP_NEG_LONG: {
1383 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1384 reg1 = NEXT_REG(reg0);
1385 reg2 = NEXT_REG(reg1);
1386 reg3 = NEXT_REG(reg2);
1387
1388 loadValuePair(cUnit, vSrc2, reg0, reg1);
1389 loadConstant(cUnit, reg3, 0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001390 opRegRegReg(cUnit, OP_SUB, reg2, reg3, reg0);
1391 opRegReg(cUnit, OP_SBC, reg3, reg1);
Ben Cheng38329f52009-07-07 14:19:20 -07001392 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001393 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001394 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001395 default:
1396 LOGE("Invalid long arith op");
1397 dvmAbort();
1398 }
1399 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001400 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1401 reg1 = NEXT_REG(reg0);
1402 reg2 = NEXT_REG(reg1);
1403 reg3 = NEXT_REG(reg2);
1404
1405 loadValuePair(cUnit, vSrc1, reg0, reg1);
1406 loadValuePair(cUnit, vSrc2, reg2, reg3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001407 opRegReg(cUnit, firstOp, reg0, reg2);
1408 opRegReg(cUnit, secondOp, reg1, reg3);
1409 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001410 /*
Bill Buzbee270c1d62009-08-13 16:58:07 -07001411 * Don't optimize the register usage here as they are governed by the EABI
Ben Chenge9695e52009-06-16 16:11:47 -07001412 * calling convention.
1413 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001414 } else {
1415 loadValuePair(cUnit, vSrc2, r2, r3);
1416 loadConstant(cUnit, r4PC, (int) callTgt);
1417 loadValuePair(cUnit, vSrc1, r0, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001418 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001419 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1420 }
1421 return false;
1422}
1423
1424static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1425 int vSrc1, int vSrc2)
1426{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001427 OpKind op = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001428 bool callOut = false;
1429 bool checkZero = false;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001430 bool threeOperand = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001431 int retReg = r0;
1432 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -07001433 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001434
1435 /* TODO - find proper .h file to declare these */
1436 int __aeabi_idivmod(int op1, int op2);
1437 int __aeabi_idiv(int op1, int op2);
1438
1439 switch (mir->dalvikInsn.opCode) {
1440 case OP_NEG_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001441 op = OP_NEG;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001442 break;
1443 case OP_NOT_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001444 op = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001445 break;
1446 case OP_ADD_INT:
1447 case OP_ADD_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001448 op = OP_ADD;
1449 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001450 break;
1451 case OP_SUB_INT:
1452 case OP_SUB_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001453 op = OP_SUB;
1454 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001455 break;
1456 case OP_MUL_INT:
1457 case OP_MUL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001458 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001459 break;
1460 case OP_DIV_INT:
1461 case OP_DIV_INT_2ADDR:
1462 callOut = true;
1463 checkZero = true;
1464 callTgt = __aeabi_idiv;
1465 retReg = r0;
1466 break;
1467 /* NOTE: returns in r1 */
1468 case OP_REM_INT:
1469 case OP_REM_INT_2ADDR:
1470 callOut = true;
1471 checkZero = true;
1472 callTgt = __aeabi_idivmod;
1473 retReg = r1;
1474 break;
1475 case OP_AND_INT:
1476 case OP_AND_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001477 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001478 break;
1479 case OP_OR_INT:
1480 case OP_OR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001481 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001482 break;
1483 case OP_XOR_INT:
1484 case OP_XOR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001485 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001486 break;
1487 case OP_SHL_INT:
1488 case OP_SHL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001489 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001490 break;
1491 case OP_SHR_INT:
1492 case OP_SHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001493 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001494 break;
1495 case OP_USHR_INT:
1496 case OP_USHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001497 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001498 break;
1499 default:
1500 LOGE("Invalid word arith op: 0x%x(%d)",
1501 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1502 dvmAbort();
1503 }
1504 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001505 /* Try to allocate reg0 to the currently cached source operand */
1506 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1507 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1508 reg1 = NEXT_REG(reg0);
1509 regDest = NEXT_REG(reg1);
1510
1511 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1512 loadValue(cUnit, vSrc2, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001513 if (threeOperand) {
1514 opRegRegReg(cUnit, op, regDest, reg0, reg1);
1515 storeValue(cUnit, regDest, vDest, reg1);
1516 } else {
1517 opRegReg(cUnit, op, reg0, reg1);
1518 storeValue(cUnit, reg0, vDest, reg1);
1519 }
Ben Chenge9695e52009-06-16 16:11:47 -07001520 } else {
1521 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1522 reg1 = NEXT_REG(reg0);
1523 regDest = NEXT_REG(reg1);
1524
1525 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1526 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001527 if (threeOperand) {
1528 opRegRegReg(cUnit, op, regDest, reg1, reg0);
1529 storeValue(cUnit, regDest, vDest, reg1);
1530 } else {
1531 opRegReg(cUnit, op, reg1, reg0);
1532 storeValue(cUnit, reg1, vDest, reg0);
1533 }
Ben Chenge9695e52009-06-16 16:11:47 -07001534 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001535 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001536 /*
1537 * Load the callout target first since it will never be eliminated
1538 * and its value will be used first.
1539 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001540 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -07001541 /*
1542 * Load vSrc2 first if it is not cached in a native register or it
1543 * is in r0 which will be clobbered if vSrc1 is loaded first.
1544 */
1545 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1546 cUnit->registerScoreboard.nativeReg == r0) {
1547 /* Cannot be optimized and won't clobber r0 */
1548 loadValue(cUnit, vSrc2, r1);
1549 /* May be optimized if vSrc1 is cached */
1550 loadValue(cUnit, vSrc1, r0);
1551 } else {
1552 loadValue(cUnit, vSrc1, r0);
1553 loadValue(cUnit, vSrc2, r1);
1554 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001555 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -07001556 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001557 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001558 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001559 storeValue(cUnit, retReg, vDest, r2);
1560 }
1561 return false;
1562}
1563
1564static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1565{
1566 OpCode opCode = mir->dalvikInsn.opCode;
1567 int vA = mir->dalvikInsn.vA;
1568 int vB = mir->dalvikInsn.vB;
1569 int vC = mir->dalvikInsn.vC;
1570
1571 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1572 return genArithOpLong(cUnit,mir, vA, vA, vB);
1573 }
1574 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1575 return genArithOpLong(cUnit,mir, vA, vB, vC);
1576 }
1577 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1578 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1579 }
1580 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1581 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1582 }
1583 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1584 return genArithOpInt(cUnit,mir, vA, vA, vB);
1585 }
1586 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1587 return genArithOpInt(cUnit,mir, vA, vB, vC);
1588 }
1589 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001590 return genArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001591 }
1592 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001593 return genArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001594 }
1595 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001596 return genArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001597 }
1598 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001599 return genArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001600 }
1601 return true;
1602}
1603
Bill Buzbeed45ba372009-06-15 17:00:57 -07001604static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1605 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001606{
Ben Chenge9695e52009-06-16 16:11:47 -07001607 /*
1608 * Don't optimize the register usage since it calls out to template
1609 * functions
1610 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001611 loadConstant(cUnit, r2, (int)funct);
1612 if (srcSize == 1) {
1613 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1614 } else {
1615 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1616 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001617 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001618 if (tgtSize == 1) {
1619 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1620 } else {
1621 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1622 }
1623 return false;
1624}
1625
Ben Chengba4fc8b2009-06-01 13:00:29 -07001626static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1627 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001628 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001629{
1630 unsigned int i;
1631 unsigned int regMask = 0;
1632
1633 /* Load arguments to r0..r4 */
1634 for (i = 0; i < dInsn->vA; i++) {
1635 regMask |= 1 << i;
1636 loadValue(cUnit, dInsn->arg[i], i);
1637 }
1638 if (regMask) {
1639 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001640 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1641 sizeof(StackSaveArea) + (dInsn->vA << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001642 /* generate null check */
1643 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001644 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1645 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001646 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001647 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001648 }
1649}
1650
1651static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1652 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001653 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001654{
1655 int srcOffset = dInsn->vC << 2;
1656 int numArgs = dInsn->vA;
1657 int regMask;
1658 /*
1659 * r4PC : &rFP[vC]
1660 * r7: &newFP[0]
1661 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001662 opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001663 /* load [r0 .. min(numArgs,4)] */
1664 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001665 /*
1666 * Protect the loadMultiple instruction from being reordered with other
1667 * Dalvik stack accesses.
1668 */
1669 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001670 loadMultiple(cUnit, r4PC, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001671 genBarrier(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001672
Bill Buzbee270c1d62009-08-13 16:58:07 -07001673 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1674 sizeof(StackSaveArea) + (numArgs << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001675 /* generate null check */
1676 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001677 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001678 }
1679
1680 /*
1681 * Handle remaining 4n arguments:
1682 * store previously loaded 4 values and load the next 4 values
1683 */
1684 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001685 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001686 /*
1687 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001688 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001689 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001690 opImm(cUnit, OP_PUSH, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001691 /* No need to generate the loop structure if numArgs <= 11 */
1692 if (numArgs > 11) {
1693 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001694 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengd7d426a2009-09-22 11:23:36 -07001695 loopLabel->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001696 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001697 storeMultiple(cUnit, r7, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001698 /*
1699 * Protect the loadMultiple instruction from being reordered with other
1700 * Dalvik stack accesses.
1701 */
1702 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001703 loadMultiple(cUnit, r4PC, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001704 genBarrier(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001705 /* No need to generate the loop structure if numArgs <= 11 */
1706 if (numArgs > 11) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001707 opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001708 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1709 }
1710 }
1711
1712 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001713 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001714
1715 /* Generate the loop epilogue - don't use r0 */
1716 if ((numArgs > 4) && (numArgs % 4)) {
1717 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001718 /*
1719 * Protect the loadMultiple instruction from being reordered with other
1720 * Dalvik stack accesses.
1721 */
1722 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001723 loadMultiple(cUnit, r4PC, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001724 genBarrier(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001725 }
1726 if (numArgs >= 8)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001727 opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001728
1729 /* Save the modulo 4 arguments */
1730 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001731 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001732 }
1733}
1734
Ben Cheng38329f52009-07-07 14:19:20 -07001735/*
1736 * Generate code to setup the call stack then jump to the chaining cell if it
1737 * is not a native method.
1738 */
1739static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001740 BasicBlock *bb, ArmLIR *labelList,
1741 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001742 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001743{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001744 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001745
1746 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001747 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001748 /* r4PC = dalvikCallsite */
1749 loadConstant(cUnit, r4PC,
1750 (int) (cUnit->method->insns + mir->offset));
1751 addrRetChain->generic.target = (LIR *) retChainingCell;
1752 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001753 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001754 * r1 = &ChainingCell
1755 * r4PC = callsiteDPC
1756 */
1757 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001758 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001759#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001760 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001761#endif
1762 } else {
1763 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1764#if defined(INVOKE_STATS)
1765 gDvmJit.invokeChain++;
1766#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001767 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001768 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1769 }
1770 /* Handle exceptions using the interpreter */
1771 genTrap(cUnit, mir->offset, pcrLabel);
1772}
1773
Ben Cheng38329f52009-07-07 14:19:20 -07001774/*
1775 * Generate code to check the validity of a predicted chain and take actions
1776 * based on the result.
1777 *
1778 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1779 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1780 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1781 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1782 * 0x426a99b2 : blx_2 see above --+
1783 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1784 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1785 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1786 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1787 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1788 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1789 * 0x426a99c0 : blx r7 --+
1790 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1791 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1792 * 0x426a99c6 : blx_2 see above --+
1793 */
1794static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1795 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001796 ArmLIR *retChainingCell,
1797 ArmLIR *predChainingCell,
1798 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001799{
1800 /* "this" is already left in r0 by genProcessArgs* */
1801
1802 /* r4PC = dalvikCallsite */
1803 loadConstant(cUnit, r4PC,
1804 (int) (cUnit->method->insns + mir->offset));
1805
1806 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001807 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001808 addrRetChain->generic.target = (LIR *) retChainingCell;
1809
1810 /* r2 = &predictedChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001811 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, OP_ADD, r2, rpc, 0,
1812 rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001813 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1814
1815 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1816
1817 /* return through lr - jump to the chaining cell */
1818 genUnconditionalBranch(cUnit, predChainingCell);
1819
1820 /*
1821 * null-check on "this" may have been eliminated, but we still need a PC-
1822 * reconstruction label for stack overflow bailout.
1823 */
1824 if (pcrLabel == NULL) {
1825 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001826 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1827 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001828 pcrLabel->operands[0] = dPC;
1829 pcrLabel->operands[1] = mir->offset;
1830 /* Insert the place holder to the growable list */
1831 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1832 }
1833
1834 /* return through lr+2 - punt to the interpreter */
1835 genUnconditionalBranch(cUnit, pcrLabel);
1836
1837 /*
1838 * return through lr+4 - fully resolve the callee method.
1839 * r1 <- count
1840 * r2 <- &predictedChainCell
1841 * r3 <- this->class
1842 * r4 <- dPC
1843 * r7 <- this->class->vtable
1844 */
1845
1846 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001847 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001848
1849 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001850 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001851
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001852 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001853 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001854
Bill Buzbee270c1d62009-08-13 16:58:07 -07001855 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1856 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001857
1858 /*
1859 * r0 = calleeMethod
1860 * r2 = &predictedChainingCell
1861 * r3 = class
1862 *
1863 * &returnChainingCell has been loaded into r1 but is not needed
1864 * when patching the chaining cell and will be clobbered upon
1865 * returning so it will be reconstructed again.
1866 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001867 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001868
1869 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001870 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001871 addrRetChain->generic.target = (LIR *) retChainingCell;
1872
1873 bypassRechaining->generic.target = (LIR *) addrRetChain;
1874 /*
1875 * r0 = calleeMethod,
1876 * r1 = &ChainingCell,
1877 * r4PC = callsiteDPC,
1878 */
1879 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1880#if defined(INVOKE_STATS)
1881 gDvmJit.invokePredictedChain++;
1882#endif
1883 /* Handle exceptions using the interpreter */
1884 genTrap(cUnit, mir->offset, pcrLabel);
1885}
1886
1887/*
1888 * Up calling this function, "this" is stored in r0. The actual class will be
1889 * chased down off r0 and the predicted one will be retrieved through
1890 * predictedChainingCell then a comparison is performed to see whether the
1891 * previously established chaining is still valid.
1892 *
1893 * The return LIR is a branch based on the comparison result. The actual branch
1894 * target will be setup in the caller.
1895 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001896static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1897 ArmLIR *predChainingCell,
1898 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001899 MIR *mir)
1900{
1901 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001902 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001903
1904 /*
1905 * r2 now contains predicted class. The starting offset of the
1906 * cached value is 4 bytes into the chaining cell.
1907 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001908 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001909 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07001910 getPredictedClass->generic.target = (LIR *) predChainingCell;
1911
1912 /*
1913 * r0 now contains predicted method. The starting offset of the
1914 * cached value is 8 bytes into the chaining cell.
1915 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001916 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001917 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001918 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1919
1920 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001921 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001922 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001923 getRechainingRequestCount->generic.target =
1924 (LIR *) predChainingCell;
1925
1926 /* r4PC = dalvikCallsite */
1927 loadConstant(cUnit, r4PC,
1928 (int) (cUnit->method->insns + mir->offset));
1929
1930 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001931 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001932 addrRetChain->generic.target = (LIR *) retChainingCell;
1933
1934 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001935 opRegReg(cUnit, OP_CMP, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001936
Bill Buzbee270c1d62009-08-13 16:58:07 -07001937 return opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001938}
1939
Ben Chengba4fc8b2009-06-01 13:00:29 -07001940/* Geneate a branch to go back to the interpreter */
1941static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1942{
1943 /* r0 = dalvik pc */
1944 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001945 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1946 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1947 jitToInterpEntries.dvmJitToInterpPunt), r1);
1948 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001949}
1950
1951/*
1952 * Attempt to single step one instruction using the interpreter and return
1953 * to the compiled code for the next Dalvik instruction
1954 */
1955static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1956{
1957 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1958 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1959 kInstrCanThrow;
1960 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1961 genPuntToInterp(cUnit, mir->offset);
1962 return;
1963 }
1964 int entryAddr = offsetof(InterpState,
1965 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001966 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001967 /* r0 = dalvik pc */
1968 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1969 /* r1 = dalvik pc of following instruction */
1970 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001971 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001972}
1973
Bill Buzbee270c1d62009-08-13 16:58:07 -07001974/* Generate conditional branch instructions */
1975static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1976 ArmConditionCode cond,
1977 ArmLIR *target)
1978{
1979 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
1980 branch->generic.target = (LIR *) target;
1981 return branch;
1982}
Ben Chengba4fc8b2009-06-01 13:00:29 -07001983
Bill Buzbee270c1d62009-08-13 16:58:07 -07001984/* Generate unconditional branch instructions */
1985static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1986{
1987 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
1988 branch->generic.target = (LIR *) target;
1989 return branch;
1990}
1991
1992/* Load the address of a Dalvik register on the frame */
1993static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
1994{
1995 return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
1996}
1997
1998/* Load a single value from rFP[src] and store them into rDest */
1999static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
2000{
2001 return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
2002}
2003
2004/* Load a word at base + displacement. Displacement must be word multiple */
2005static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
2006 int rDest)
2007{
2008 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
2009 -1);
2010}
2011
2012static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
2013 int displacement, int rSrc, int rScratch)
2014{
2015 return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
2016}
2017
2018/* Store a value from rSrc to vDest */
2019static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
2020 int rScratch)
2021{
2022 killNullCheckedRegister(cUnit, vDest);
2023 updateLiveRegister(cUnit, vDest, rSrc);
2024 return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
2025}
2026/*
2027 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
2028 * rDestHi
2029 */
2030static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
2031 int rDestHi)
2032{
2033 ArmLIR *res;
2034 /* Use reg + imm5*4 to load the values if possible */
2035 if (vSrc <= 30) {
2036 res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
2037 loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
2038 } else {
2039 assert(rDestLo < rDestHi);
2040 res = loadValueAddress(cUnit, vSrc, rDestLo);
Ben Chengd7d426a2009-09-22 11:23:36 -07002041 /*
2042 * Protect the loadMultiple instruction from being reordered with other
2043 * Dalvik stack accesses.
2044 */
2045 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002046 loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
Ben Chengd7d426a2009-09-22 11:23:36 -07002047 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002048 }
2049 return res;
2050}
2051
2052/*
2053 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
2054 * vDest+1
2055 */
2056static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
2057 int vDest, int rScratch)
2058{
2059 ArmLIR *res;
2060 killNullCheckedRegister(cUnit, vDest);
2061 killNullCheckedRegister(cUnit, vDest+1);
2062 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
2063
2064 /* Use reg + imm5*4 to store the values if possible */
2065 if (vDest <= 30) {
2066 res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
2067 storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
2068 } else {
2069 assert(rSrcLo < rSrcHi);
2070 res = loadValueAddress(cUnit, vDest, rScratch);
Ben Chengd7d426a2009-09-22 11:23:36 -07002071 /*
2072 * Protect the storeMultiple instruction from being reordered with
2073 * other Dalvik stack accesses.
2074 */
2075 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002076 storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
Ben Chengd7d426a2009-09-22 11:23:36 -07002077 genBarrier(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002078 }
2079 return res;
2080}
2081
2082static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
2083{
2084 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
2085 dvmCompilerAppendLIR(cUnit, (LIR*)res);
2086 return res;
2087}
2088
Ben Chengba4fc8b2009-06-01 13:00:29 -07002089/*
2090 * The following are the first-level codegen routines that analyze the format
2091 * of each bytecode then either dispatch special purpose codegen routines
2092 * or produce corresponding Thumb instructions directly.
2093 */
2094
2095static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002096 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002097{
2098 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2099 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2100 return false;
2101}
2102
2103static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
2104{
2105 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2106 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
2107 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
2108 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2109 return true;
2110 }
2111 switch (dalvikOpCode) {
2112 case OP_RETURN_VOID:
2113 genReturnCommon(cUnit,mir);
2114 break;
2115 case OP_UNUSED_73:
2116 case OP_UNUSED_79:
2117 case OP_UNUSED_7A:
2118 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2119 return true;
2120 case OP_NOP:
2121 break;
2122 default:
2123 return true;
2124 }
2125 return false;
2126}
2127
2128static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2129{
Ben Chenge9695e52009-06-16 16:11:47 -07002130 int reg0, reg1, reg2;
2131
Ben Chengba4fc8b2009-06-01 13:00:29 -07002132 switch (mir->dalvikInsn.opCode) {
2133 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07002134 case OP_CONST_4: {
2135 /* Avoid using the previously used register */
2136 reg0 = selectFirstRegister(cUnit, vNone, false);
2137 reg1 = NEXT_REG(reg0);
2138 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
2139 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002140 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002141 }
2142 case OP_CONST_WIDE_32: {
2143 /* Avoid using the previously used register */
2144 reg0 = selectFirstRegister(cUnit, vNone, true);
2145 reg1 = NEXT_REG(reg0);
2146 reg2 = NEXT_REG(reg1);
2147 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002148 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002149 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002150 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002151 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002152 default:
2153 return true;
2154 }
2155 return false;
2156}
2157
2158static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2159{
Ben Chenge9695e52009-06-16 16:11:47 -07002160 int reg0, reg1, reg2;
2161
2162 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002163 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07002164 case OP_CONST_HIGH16: {
2165 reg0 = selectFirstRegister(cUnit, vNone, false);
2166 reg1 = NEXT_REG(reg0);
2167 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
2168 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002169 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002170 }
2171 case OP_CONST_WIDE_HIGH16: {
2172 reg0 = selectFirstRegister(cUnit, vNone, true);
2173 reg1 = NEXT_REG(reg0);
2174 reg2 = NEXT_REG(reg1);
2175 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
2176 loadConstant(cUnit, reg0, 0);
2177 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002178 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002179 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002180 default:
2181 return true;
2182 }
2183 return false;
2184}
2185
2186static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2187{
2188 /* For OP_THROW_VERIFICATION_ERROR */
2189 genInterpSingleStep(cUnit, mir);
2190 return false;
2191}
2192
2193static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2194{
Ben Chenge9695e52009-06-16 16:11:47 -07002195 /* Native register to use if the interested value is vA */
2196 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2197 /* Native register to use if source is not from Dalvik registers */
2198 int regvNone = selectFirstRegister(cUnit, vNone, false);
2199 /* Similar to regvA but for 64-bit values */
2200 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
2201 /* Similar to regvNone but for 64-bit values */
2202 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
2203
Ben Chengba4fc8b2009-06-01 13:00:29 -07002204 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002205 case OP_CONST_STRING_JUMBO:
2206 case OP_CONST_STRING: {
2207 void *strPtr = (void*)
2208 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2209 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002210 loadConstant(cUnit, regvNone, (int) strPtr );
2211 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002212 break;
2213 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002214 case OP_CONST_CLASS: {
2215 void *classPtr = (void*)
2216 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2217 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002218 loadConstant(cUnit, regvNone, (int) classPtr );
2219 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002220 break;
2221 }
2222 case OP_SGET_OBJECT:
2223 case OP_SGET_BOOLEAN:
2224 case OP_SGET_CHAR:
2225 case OP_SGET_BYTE:
2226 case OP_SGET_SHORT:
2227 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002228 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002229 void *fieldPtr = (void*)
2230 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2231 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002232 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002233#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002234 loadWordDisp(cUnit, regvNone, 0, regvNone);
Jeff Hao97319a82009-08-12 16:57:15 -07002235#else
2236 int regMap = regvNone << 4 | regvNone;
2237 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2238
Jeff Hao97319a82009-08-12 16:57:15 -07002239#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002240 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002241 break;
2242 }
2243 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002244 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002245 void *fieldPtr = (void*)
2246 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002247 int reg0, reg1, reg2;
2248
Ben Chengba4fc8b2009-06-01 13:00:29 -07002249 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002250 reg0 = regvNoneWide;
2251 reg1 = NEXT_REG(reg0);
2252 reg2 = NEXT_REG(reg1);
2253 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002254#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002255 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002256#else
2257 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2258 selfVerificationMemOpWrapper(cUnit, regMap,
2259 &selfVerificationLoadDoubleword);
2260
Jeff Hao97319a82009-08-12 16:57:15 -07002261#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002262 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002263 break;
2264 }
2265 case OP_SPUT_OBJECT:
2266 case OP_SPUT_BOOLEAN:
2267 case OP_SPUT_CHAR:
2268 case OP_SPUT_BYTE:
2269 case OP_SPUT_SHORT:
2270 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002271 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002272 void *fieldPtr = (void*)
2273 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002274
Ben Chengba4fc8b2009-06-01 13:00:29 -07002275 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002276 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
2277 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
2278 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002279#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002280 storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
Jeff Hao97319a82009-08-12 16:57:15 -07002281#else
2282 int regMap = regvA << 4 | NEXT_REG(regvA);
2283 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2284#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002285 break;
2286 }
2287 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002288 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002289 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002290 void *fieldPtr = (void*)
2291 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002292
Ben Chengba4fc8b2009-06-01 13:00:29 -07002293 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002294 reg0 = regvAWide;
2295 reg1 = NEXT_REG(reg0);
2296 reg2 = NEXT_REG(reg1);
2297 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2298 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2299 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002300#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002301 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002302#else
2303 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2304 selfVerificationMemOpWrapper(cUnit, regMap,
2305 &selfVerificationStoreDoubleword);
2306#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002307 break;
2308 }
2309 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002310 /*
2311 * Obey the calling convention and don't mess with the register
2312 * usage.
2313 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002314 ClassObject *classPtr = (void*)
2315 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2316 assert(classPtr != NULL);
2317 assert(classPtr->status & CLASS_INITIALIZED);
2318 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
2319 /* It's going to throw, just let the interp. deal with it. */
2320 genInterpSingleStep(cUnit, mir);
2321 return false;
2322 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002323 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002324 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002325 genExportPC(cUnit, mir, r2, r3 );
2326 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002327 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002328 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002329 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2330 break;
2331 }
2332 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002333 /*
2334 * Obey the calling convention and don't mess with the register
2335 * usage.
2336 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002337 ClassObject *classPtr =
2338 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2339 loadConstant(cUnit, r1, (int) classPtr );
2340 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002341 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* Null? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002342 ArmLIR *branch1 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002343 opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002344 /* r0 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002345 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002346 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002347 opRegReg(cUnit, OP_CMP, r0, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002348 ArmLIR *branch2 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002349 opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2350 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002351 /* check cast failed - punt to the interpreter */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002352 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002353 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002354 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengd7d426a2009-09-22 11:23:36 -07002355 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002356 branch1->generic.target = (LIR *)target;
2357 branch2->generic.target = (LIR *)target;
2358 break;
2359 }
2360 default:
2361 return true;
2362 }
2363 return false;
2364}
2365
2366static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2367{
2368 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2369 switch (dalvikOpCode) {
2370 case OP_MOVE_EXCEPTION: {
2371 int offset = offsetof(InterpState, self);
2372 int exOffset = offsetof(Thread, exception);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002373 loadWordDisp(cUnit, rGLUE, offset, r1);
2374 loadWordDisp(cUnit, r1, exOffset, r0);
Ben Chenge9695e52009-06-16 16:11:47 -07002375 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002376 break;
2377 }
2378 case OP_MOVE_RESULT:
2379 case OP_MOVE_RESULT_OBJECT: {
2380 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002381 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002382 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2383 break;
2384 }
2385 case OP_MOVE_RESULT_WIDE: {
2386 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002387 loadWordDisp(cUnit, rGLUE, offset, r0);
2388 loadWordDisp(cUnit, rGLUE, offset+4, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002389 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2390 break;
2391 }
2392 case OP_RETURN_WIDE: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002393 int vSrc = mir->dalvikInsn.vA;
2394 int reg0 = selectFirstRegister(cUnit, vSrc, true);
2395 int reg1 = NEXT_REG(reg0);
2396 int rScratch = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002397 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002398 loadValuePair(cUnit, vSrc, reg0, reg1);
2399 storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
2400 storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002401 genReturnCommon(cUnit,mir);
2402 break;
2403 }
2404 case OP_RETURN:
2405 case OP_RETURN_OBJECT: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002406 int vSrc = mir->dalvikInsn.vA;
2407 int reg0 = selectFirstRegister(cUnit, vSrc, false);
2408 int rScratch = NEXT_REG(reg0);
2409 loadValue(cUnit, vSrc, reg0);
2410 storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
2411 reg0, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002412 genReturnCommon(cUnit,mir);
2413 break;
2414 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002415 case OP_MONITOR_ENTER:
2416 case OP_MONITOR_EXIT: {
2417 int offset = offsetof(InterpState, self);
2418 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002419 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002420 if (dalvikOpCode == OP_MONITOR_ENTER) {
2421 loadConstant(cUnit, r2, (int)dvmLockObject);
2422 } else {
2423 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2424 }
Ben Chenge9695e52009-06-16 16:11:47 -07002425 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002426 /* Do the call */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002427 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002428 break;
2429 }
2430 case OP_THROW: {
2431 genInterpSingleStep(cUnit, mir);
2432 break;
2433 }
2434 default:
2435 return true;
2436 }
2437 return false;
2438}
2439
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002440static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002441{
2442 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002443
Ben Chengba4fc8b2009-06-01 13:00:29 -07002444 float __aeabi_i2f( int op1 );
2445 int __aeabi_f2iz( float op1 );
2446 float __aeabi_d2f( double op1 );
2447 double __aeabi_f2d( float op1 );
2448 double __aeabi_i2d( int op1 );
2449 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002450 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002451 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002452 s8 dvmJitf2l( float op1 );
2453 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002454
Bill Buzbeed45ba372009-06-15 17:00:57 -07002455 switch (opCode) {
2456 case OP_INT_TO_FLOAT:
2457 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2458 case OP_FLOAT_TO_INT:
2459 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2460 case OP_DOUBLE_TO_FLOAT:
2461 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2462 case OP_FLOAT_TO_DOUBLE:
2463 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2464 case OP_INT_TO_DOUBLE:
2465 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2466 case OP_DOUBLE_TO_INT:
2467 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2468 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002469 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002470 case OP_LONG_TO_FLOAT:
2471 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2472 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002473 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002474 case OP_LONG_TO_DOUBLE:
2475 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2476 default:
2477 return true;
2478 }
2479 return false;
2480}
2481
2482static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2483{
2484 OpCode opCode = mir->dalvikInsn.opCode;
2485 int vSrc1Dest = mir->dalvikInsn.vA;
2486 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002487 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002488
Ben Chengba4fc8b2009-06-01 13:00:29 -07002489 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2490 return genArithOp( cUnit, mir );
2491 }
2492
Ben Chenge9695e52009-06-16 16:11:47 -07002493 /*
2494 * If data type is 64-bit, re-calculate the register numbers in the
2495 * corresponding cases.
2496 */
2497 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2498 reg1 = NEXT_REG(reg0);
2499 reg2 = NEXT_REG(reg1);
2500
Ben Chengba4fc8b2009-06-01 13:00:29 -07002501 switch (opCode) {
2502 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002503 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002504 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002505 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002506 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002507 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002508 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002509 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002510 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002511 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002512 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002513 case OP_NEG_INT:
2514 case OP_NOT_INT:
2515 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2516 case OP_NEG_LONG:
2517 case OP_NOT_LONG:
2518 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2519 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002520 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002521 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002522 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07002523 case OP_MOVE_WIDE: {
2524 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2525 reg1 = NEXT_REG(reg0);
2526 reg2 = NEXT_REG(reg1);
2527
2528 loadValuePair(cUnit, vSrc2, reg0, reg1);
2529 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002530 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002531 }
2532 case OP_INT_TO_LONG: {
2533 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2534 reg1 = NEXT_REG(reg0);
2535 reg2 = NEXT_REG(reg1);
2536
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002537 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002538 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002539 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002540 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002541 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002542 case OP_MOVE:
2543 case OP_MOVE_OBJECT:
2544 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002545 loadValue(cUnit, vSrc2, reg0);
2546 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002547 break;
2548 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07002549 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002550 opRegReg(cUnit, OP_2BYTE, reg1, reg0);
2551 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002552 break;
2553 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07002554 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002555 opRegReg(cUnit, OP_2SHORT, reg1, reg0);
2556 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002557 break;
2558 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07002559 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002560 opRegReg(cUnit, OP_2CHAR, reg1, reg0);
2561 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002562 break;
2563 case OP_ARRAY_LENGTH: {
2564 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002565 loadValue(cUnit, vSrc2, reg1);
2566 genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
2567 loadWordDisp(cUnit, reg1, lenOffset, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -07002568 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002569 break;
2570 }
2571 default:
2572 return true;
2573 }
2574 return false;
2575}
2576
2577static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2578{
2579 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07002580 int reg0, reg1, reg2;
2581
Ben Chengba4fc8b2009-06-01 13:00:29 -07002582 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2583 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002584 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002585 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002586
2587 reg0 = selectFirstRegister(cUnit, vNone, true);
2588 reg1 = NEXT_REG(reg0);
2589 reg2 = NEXT_REG(reg1);
2590
2591 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002592 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002593
2594 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07002595 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002596 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002597 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002598 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002599
Ben Chenge9695e52009-06-16 16:11:47 -07002600 reg0 = selectFirstRegister(cUnit, vNone, false);
2601 reg1 = NEXT_REG(reg0);
2602
2603 loadConstant(cUnit, reg0, BBBB);
2604 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002605 } else {
2606 return true;
2607 }
2608 return false;
2609}
2610
2611/* Compare agaist zero */
2612static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002613 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002614{
2615 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002616 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002617 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002618
Ben Chenge9695e52009-06-16 16:11:47 -07002619 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002620 opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002621
Bill Buzbee270c1d62009-08-13 16:58:07 -07002622//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002623 switch (dalvikOpCode) {
2624 case OP_IF_EQZ:
2625 cond = ARM_COND_EQ;
2626 break;
2627 case OP_IF_NEZ:
2628 cond = ARM_COND_NE;
2629 break;
2630 case OP_IF_LTZ:
2631 cond = ARM_COND_LT;
2632 break;
2633 case OP_IF_GEZ:
2634 cond = ARM_COND_GE;
2635 break;
2636 case OP_IF_GTZ:
2637 cond = ARM_COND_GT;
2638 break;
2639 case OP_IF_LEZ:
2640 cond = ARM_COND_LE;
2641 break;
2642 default:
2643 cond = 0;
2644 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2645 dvmAbort();
2646 }
2647 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2648 /* This mostly likely will be optimized away in a later phase */
2649 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2650 return false;
2651}
2652
2653static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2654{
2655 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2656 int vSrc = mir->dalvikInsn.vB;
2657 int vDest = mir->dalvikInsn.vA;
2658 int lit = mir->dalvikInsn.vC;
Bill Buzbee270c1d62009-08-13 16:58:07 -07002659 OpKind op;
Ben Chenge9695e52009-06-16 16:11:47 -07002660 int reg0, reg1, regDest;
2661
2662 reg0 = selectFirstRegister(cUnit, vSrc, false);
2663 reg1 = NEXT_REG(reg0);
2664 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002665
Ben Chengba4fc8b2009-06-01 13:00:29 -07002666 int __aeabi_idivmod(int op1, int op2);
2667 int __aeabi_idiv(int op1, int op2);
2668
2669 switch (dalvikOpCode) {
2670 case OP_ADD_INT_LIT8:
2671 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002672 loadValue(cUnit, vSrc, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002673 opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
2674 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002675 break;
2676
2677 case OP_RSUB_INT_LIT8:
2678 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002679 loadValue(cUnit, vSrc, reg1);
2680 loadConstant(cUnit, reg0, lit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002681 opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
2682 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002683 break;
2684
2685 case OP_MUL_INT_LIT8:
2686 case OP_MUL_INT_LIT16:
2687 case OP_AND_INT_LIT8:
2688 case OP_AND_INT_LIT16:
2689 case OP_OR_INT_LIT8:
2690 case OP_OR_INT_LIT16:
2691 case OP_XOR_INT_LIT8:
2692 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002693 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002694 switch (dalvikOpCode) {
2695 case OP_MUL_INT_LIT8:
2696 case OP_MUL_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002697 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002698 break;
2699 case OP_AND_INT_LIT8:
2700 case OP_AND_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002701 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002702 break;
2703 case OP_OR_INT_LIT8:
2704 case OP_OR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002705 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002706 break;
2707 case OP_XOR_INT_LIT8:
2708 case OP_XOR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002709 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002710 break;
2711 default:
2712 dvmAbort();
2713 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002714 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2715 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002716 break;
2717
2718 case OP_SHL_INT_LIT8:
2719 case OP_SHR_INT_LIT8:
2720 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002721 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002722 switch (dalvikOpCode) {
2723 case OP_SHL_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002724 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002725 break;
2726 case OP_SHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002727 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002728 break;
2729 case OP_USHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002730 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002731 break;
2732 default: dvmAbort();
2733 }
Bill Buzbeea6f40f12009-09-22 09:45:41 -07002734 if (lit != 0) {
2735 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2736 storeValue(cUnit, regDest, vDest, reg1);
2737 } else {
2738 storeValue(cUnit, reg0, vDest, reg1);
2739 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002740 break;
2741
2742 case OP_DIV_INT_LIT8:
2743 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002744 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002745 if (lit == 0) {
2746 /* Let the interpreter deal with div by 0 */
2747 genInterpSingleStep(cUnit, mir);
2748 return false;
2749 }
2750 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2751 loadConstant(cUnit, r1, lit);
2752 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002753 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002754 storeValue(cUnit, r0, vDest, r2);
2755 break;
2756
2757 case OP_REM_INT_LIT8:
2758 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002759 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002760 if (lit == 0) {
2761 /* Let the interpreter deal with div by 0 */
2762 genInterpSingleStep(cUnit, mir);
2763 return false;
2764 }
2765 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2766 loadConstant(cUnit, r1, lit);
2767 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002768 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002769 storeValue(cUnit, r1, vDest, r2);
2770 break;
2771 default:
2772 return true;
2773 }
2774 return false;
2775}
2776
2777static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2778{
2779 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2780 int fieldOffset;
2781
2782 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2783 InstField *pInstField = (InstField *)
2784 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2785 int fieldOffset;
2786
2787 assert(pInstField != NULL);
2788 fieldOffset = pInstField->byteOffset;
2789 } else {
2790 /* To make the compiler happy */
2791 fieldOffset = 0;
2792 }
2793 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002794 case OP_NEW_ARRAY: {
2795 void *classPtr = (void*)
2796 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2797 assert(classPtr != NULL);
2798 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2799 loadConstant(cUnit, r0, (int) classPtr );
2800 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002801 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002802 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2803 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002804 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2805 opReg(cUnit, OP_BLX, r4PC);
2806 /* Note: on failure, we'll bail and reinterpret */
Ben Chenge9695e52009-06-16 16:11:47 -07002807 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002808 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2809 break;
2810 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002811 case OP_INSTANCE_OF: {
2812 ClassObject *classPtr =
2813 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2814 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002815 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002816 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002817//TUNING: compare to 0 primative to allow use of CB[N]Z
2818 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002819 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002820 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002821 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002822 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002823 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002824 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002825 opRegReg(cUnit, OP_CMP, r1, r2);
2826 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2827 opRegReg(cUnit, OP_MOV, r0, r1);
2828 opRegReg(cUnit, OP_MOV, r1, r2);
2829 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002830 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002831 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengd7d426a2009-09-22 11:23:36 -07002832 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002833 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2834 branch1->generic.target = (LIR *)target;
2835 branch2->generic.target = (LIR *)target;
2836 break;
2837 }
2838 case OP_IGET_WIDE:
2839 genIGetWide(cUnit, mir, fieldOffset);
2840 break;
2841 case OP_IGET:
2842 case OP_IGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002843 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002844 break;
2845 case OP_IGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002846 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002847 break;
2848 case OP_IGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002849 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002850 break;
2851 case OP_IGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002852 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002853 break;
2854 case OP_IGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002855 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002856 break;
2857 case OP_IPUT_WIDE:
2858 genIPutWide(cUnit, mir, fieldOffset);
2859 break;
2860 case OP_IPUT:
2861 case OP_IPUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002862 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002863 break;
2864 case OP_IPUT_SHORT:
2865 case OP_IPUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002866 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002867 break;
2868 case OP_IPUT_BYTE:
2869 case OP_IPUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002870 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002871 break;
2872 default:
2873 return true;
2874 }
2875 return false;
2876}
2877
2878static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2879{
2880 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2881 int fieldOffset = mir->dalvikInsn.vC;
2882 switch (dalvikOpCode) {
2883 case OP_IGET_QUICK:
2884 case OP_IGET_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002885 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002886 break;
2887 case OP_IPUT_QUICK:
2888 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002889 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002890 break;
2891 case OP_IGET_WIDE_QUICK:
2892 genIGetWide(cUnit, mir, fieldOffset);
2893 break;
2894 case OP_IPUT_WIDE_QUICK:
2895 genIPutWide(cUnit, mir, fieldOffset);
2896 break;
2897 default:
2898 return true;
2899 }
2900 return false;
2901
2902}
2903
2904/* Compare agaist zero */
2905static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002906 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002907{
2908 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002909 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002910 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002911
Ben Chenge9695e52009-06-16 16:11:47 -07002912 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2913 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2914 reg1 = NEXT_REG(reg0);
2915 /* Load vB first since vA can be fetched via a move */
2916 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2917 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2918 } else {
2919 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2920 reg1 = NEXT_REG(reg0);
2921 /* Load vA first since vB can be fetched via a move */
2922 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2923 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2924 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002925 opRegReg(cUnit, OP_CMP, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002926
2927 switch (dalvikOpCode) {
2928 case OP_IF_EQ:
2929 cond = ARM_COND_EQ;
2930 break;
2931 case OP_IF_NE:
2932 cond = ARM_COND_NE;
2933 break;
2934 case OP_IF_LT:
2935 cond = ARM_COND_LT;
2936 break;
2937 case OP_IF_GE:
2938 cond = ARM_COND_GE;
2939 break;
2940 case OP_IF_GT:
2941 cond = ARM_COND_GT;
2942 break;
2943 case OP_IF_LE:
2944 cond = ARM_COND_LE;
2945 break;
2946 default:
2947 cond = 0;
2948 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2949 dvmAbort();
2950 }
2951 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2952 /* This mostly likely will be optimized away in a later phase */
2953 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2954 return false;
2955}
2956
2957static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2958{
2959 OpCode opCode = mir->dalvikInsn.opCode;
2960 int vSrc1Dest = mir->dalvikInsn.vA;
2961 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002962 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002963
2964 switch (opCode) {
2965 case OP_MOVE_16:
2966 case OP_MOVE_OBJECT_16:
2967 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002968 case OP_MOVE_OBJECT_FROM16: {
2969 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2970 reg1 = NEXT_REG(reg0);
2971 loadValue(cUnit, vSrc2, reg0);
2972 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002973 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002974 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002975 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002976 case OP_MOVE_WIDE_FROM16: {
2977 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2978 reg1 = NEXT_REG(reg0);
2979 reg2 = NEXT_REG(reg1);
2980 loadValuePair(cUnit, vSrc2, reg0, reg1);
2981 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002982 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002983 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002984 default:
2985 return true;
2986 }
2987 return false;
2988}
2989
2990static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2991{
2992 OpCode opCode = mir->dalvikInsn.opCode;
2993 int vA = mir->dalvikInsn.vA;
2994 int vB = mir->dalvikInsn.vB;
2995 int vC = mir->dalvikInsn.vC;
2996
Ben Chenge9695e52009-06-16 16:11:47 -07002997 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002998 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2999 return genArithOp( cUnit, mir );
3000 }
3001
3002 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07003003 case OP_CMPL_FLOAT:
3004 case OP_CMPG_FLOAT:
3005 case OP_CMPL_DOUBLE:
3006 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003007 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003008 case OP_CMP_LONG:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07003009 genCmpLong(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003010 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003011 case OP_AGET_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003012 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003013 break;
3014 case OP_AGET:
3015 case OP_AGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003016 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003017 break;
3018 case OP_AGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003019 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003020 break;
3021 case OP_AGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003022 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003023 break;
3024 case OP_AGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003025 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003026 break;
3027 case OP_AGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003028 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003029 break;
3030 case OP_APUT_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003031 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003032 break;
3033 case OP_APUT:
3034 case OP_APUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003035 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003036 break;
3037 case OP_APUT_SHORT:
3038 case OP_APUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003039 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003040 break;
3041 case OP_APUT_BYTE:
3042 case OP_APUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07003043 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003044 break;
3045 default:
3046 return true;
3047 }
3048 return false;
3049}
3050
3051static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
3052{
3053 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3054 switch (dalvikOpCode) {
3055 case OP_FILL_ARRAY_DATA: {
3056 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
3057 loadValue(cUnit, mir->dalvikInsn.vA, r0);
3058 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
3059 (int) (cUnit->method->insns + mir->offset));
3060 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07003061 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07003062 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003063 break;
3064 }
3065 /*
3066 * TODO
3067 * - Add a 1 to 3-entry per-location cache here to completely
3068 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
3069 * - Use out-of-line handlers for both of these
3070 */
3071 case OP_PACKED_SWITCH:
3072 case OP_SPARSE_SWITCH: {
3073 if (dalvikOpCode == OP_PACKED_SWITCH) {
3074 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
3075 } else {
3076 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
3077 }
3078 loadValue(cUnit, mir->dalvikInsn.vA, r1);
3079 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
3080 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07003081 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003082 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07003083 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3084 jitToInterpEntries.dvmJitToInterpNoChain), r2);
3085 opRegReg(cUnit, OP_ADD, r0, r0);
3086 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
3087 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003088 break;
3089 }
3090 default:
3091 return true;
3092 }
3093 return false;
3094}
3095
3096static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003097 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003098{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003099 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003100 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003101
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003102 if (bb->fallThrough != NULL)
3103 retChainingCell = &labelList[bb->fallThrough->id];
3104
Ben Chengba4fc8b2009-06-01 13:00:29 -07003105 DecodedInstruction *dInsn = &mir->dalvikInsn;
3106 switch (mir->dalvikInsn.opCode) {
3107 /*
3108 * calleeMethod = this->clazz->vtable[
3109 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3110 * ]
3111 */
3112 case OP_INVOKE_VIRTUAL:
3113 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003114 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003115 int methodIndex =
3116 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3117 methodIndex;
3118
3119 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3120 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3121 else
3122 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3123
Ben Cheng38329f52009-07-07 14:19:20 -07003124 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3125 retChainingCell,
3126 predChainingCell,
3127 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003128 break;
3129 }
3130 /*
3131 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3132 * ->pResMethods[BBBB]->methodIndex]
3133 */
3134 /* TODO - not excersized in RunPerf.jar */
3135 case OP_INVOKE_SUPER:
3136 case OP_INVOKE_SUPER_RANGE: {
3137 int mIndex = cUnit->method->clazz->pDvmDex->
3138 pResMethods[dInsn->vB]->methodIndex;
3139 const Method *calleeMethod =
3140 cUnit->method->clazz->super->vtable[mIndex];
3141
3142 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3143 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3144 else
3145 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3146
3147 /* r0 = calleeMethod */
3148 loadConstant(cUnit, r0, (int) calleeMethod);
3149
Ben Cheng38329f52009-07-07 14:19:20 -07003150 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3151 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003152 break;
3153 }
3154 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3155 case OP_INVOKE_DIRECT:
3156 case OP_INVOKE_DIRECT_RANGE: {
3157 const Method *calleeMethod =
3158 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3159
3160 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3161 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3162 else
3163 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3164
3165 /* r0 = calleeMethod */
3166 loadConstant(cUnit, r0, (int) calleeMethod);
3167
Ben Cheng38329f52009-07-07 14:19:20 -07003168 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3169 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003170 break;
3171 }
3172 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3173 case OP_INVOKE_STATIC:
3174 case OP_INVOKE_STATIC_RANGE: {
3175 const Method *calleeMethod =
3176 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3177
3178 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3179 genProcessArgsNoRange(cUnit, mir, dInsn,
3180 NULL /* no null check */);
3181 else
3182 genProcessArgsRange(cUnit, mir, dInsn,
3183 NULL /* no null check */);
3184
3185 /* r0 = calleeMethod */
3186 loadConstant(cUnit, r0, (int) calleeMethod);
3187
Ben Cheng38329f52009-07-07 14:19:20 -07003188 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3189 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003190 break;
3191 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07003192/*
3193 * TODO: When we move to using upper registers in Thumb2, make sure
3194 * the register allocater is told that r9, r10, & r12 are killed
3195 * here.
3196 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003197 /*
3198 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3199 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003200 *
3201 * Given "invoke-interface {v0}", the following is the generated code:
3202 *
3203 * 0x426a9abe : ldr r0, [r5, #0] --+
3204 * 0x426a9ac0 : mov r7, r5 |
3205 * 0x426a9ac2 : sub r7, #24 |
3206 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3207 * 0x426a9ac6 : beq 0x426a9afe |
3208 * 0x426a9ac8 : stmia r7, <r0> --+
3209 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3210 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3211 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3212 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3213 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3214 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3215 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
3216 * 0x426a9ad8 : mov r9, r1 --+
3217 * 0x426a9ada : mov r10, r2 |
3218 * 0x426a9adc : mov r12, r3 |
3219 * 0x426a9ade : mov r0, r3 |
3220 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3221 * 0x426a9ae2 : ldr r2, [pc, #76] |
3222 * 0x426a9ae4 : ldr r3, [pc, #68] |
3223 * 0x426a9ae6 : ldr r7, [pc, #64] |
3224 * 0x426a9ae8 : blx r7 --+
3225 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
3226 * 0x426a9aec : cmp r1, #0 --> compare against 0
3227 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3228 * 0x426a9af0 : ldr r7, [r6, #96] --+
3229 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3230 * 0x426a9af4 : mov r3, r12 |
3231 * 0x426a9af6 : blx r7 --+
3232 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3233 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3234 * 0x426a9afc : blx_2 see above --+
3235 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3236 * 0x426a9afe (0042): ldr r0, [pc, #52]
3237 * Exception_Handling:
3238 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3239 * 0x426a9b02 (0046): blx r1
3240 * 0x426a9b04 (0048): .align4
3241 * -------- chaining cell (hot): 0x0021
3242 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3243 * 0x426a9b06 (004a): blx r0
3244 * 0x426a9b08 (004c): data 0x7872(30834)
3245 * 0x426a9b0a (004e): data 0x428b(17035)
3246 * 0x426a9b0c (0050): .align4
3247 * -------- chaining cell (predicted)
3248 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3249 * 0x426a9b0e (0052): data 0x0000(0)
3250 * 0x426a9b10 (0054): data 0x0000(0) --> class
3251 * 0x426a9b12 (0056): data 0x0000(0)
3252 * 0x426a9b14 (0058): data 0x0000(0) --> method
3253 * 0x426a9b16 (005a): data 0x0000(0)
3254 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3255 * 0x426a9b1a (005e): data 0x0000(0)
3256 * 0x426a9b28 (006c): .word (0xad0392a5)
3257 * 0x426a9b2c (0070): .word (0x6e750)
3258 * 0x426a9b30 (0074): .word (0x4109a618)
3259 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003260 */
3261 case OP_INVOKE_INTERFACE:
3262 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003263 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003264 int methodIndex = dInsn->vB;
3265
3266 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3267 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3268 else
3269 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3270
Ben Cheng38329f52009-07-07 14:19:20 -07003271 /* "this" is already left in r0 by genProcessArgs* */
3272
3273 /* r4PC = dalvikCallsite */
3274 loadConstant(cUnit, r4PC,
3275 (int) (cUnit->method->insns + mir->offset));
3276
3277 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003278 ArmLIR *addrRetChain =
3279 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003280 addrRetChain->generic.target = (LIR *) retChainingCell;
3281
3282 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003283 ArmLIR *predictedChainingCell =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003284 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003285 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3286
3287 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3288
3289 /* return through lr - jump to the chaining cell */
3290 genUnconditionalBranch(cUnit, predChainingCell);
3291
3292 /*
3293 * null-check on "this" may have been eliminated, but we still need
3294 * a PC-reconstruction label for stack overflow bailout.
3295 */
3296 if (pcrLabel == NULL) {
3297 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003298 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3299 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003300 pcrLabel->operands[0] = dPC;
3301 pcrLabel->operands[1] = mir->offset;
3302 /* Insert the place holder to the growable list */
3303 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3304 }
3305
3306 /* return through lr+2 - punt to the interpreter */
3307 genUnconditionalBranch(cUnit, pcrLabel);
3308
3309 /*
3310 * return through lr+4 - fully resolve the callee method.
3311 * r1 <- count
3312 * r2 <- &predictedChainCell
3313 * r3 <- this->class
3314 * r4 <- dPC
3315 * r7 <- this->class->vtable
3316 */
3317
3318 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003319 opRegReg(cUnit, OP_MOV, r9, r1);
3320 opRegReg(cUnit, OP_MOV, r10, r2);
3321 opRegReg(cUnit, OP_MOV, r12, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003322
Ben Chengba4fc8b2009-06-01 13:00:29 -07003323 /* r0 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003324 opRegReg(cUnit, OP_MOV, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003325
3326 /* r1 = BBBB */
3327 loadConstant(cUnit, r1, dInsn->vB);
3328
3329 /* r2 = method (caller) */
3330 loadConstant(cUnit, r2, (int) cUnit->method);
3331
3332 /* r3 = pDvmDex */
3333 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3334
3335 loadConstant(cUnit, r7,
3336 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003337 opReg(cUnit, OP_BLX, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003338
3339 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3340
Bill Buzbee270c1d62009-08-13 16:58:07 -07003341 opRegReg(cUnit, OP_MOV, r1, r9);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003342
Ben Cheng38329f52009-07-07 14:19:20 -07003343 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003344 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003345
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003346 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003347 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07003348
Bill Buzbee270c1d62009-08-13 16:58:07 -07003349 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3350 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003351
Bill Buzbee270c1d62009-08-13 16:58:07 -07003352 opRegReg(cUnit, OP_MOV, r2, r10);
3353 opRegReg(cUnit, OP_MOV, r3, r12);
Ben Cheng38329f52009-07-07 14:19:20 -07003354
3355 /*
3356 * r0 = calleeMethod
3357 * r2 = &predictedChainingCell
3358 * r3 = class
3359 *
3360 * &returnChainingCell has been loaded into r1 but is not needed
3361 * when patching the chaining cell and will be clobbered upon
3362 * returning so it will be reconstructed again.
3363 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003364 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003365
3366 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003367 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003368 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003369
3370 bypassRechaining->generic.target = (LIR *) addrRetChain;
3371
Ben Chengba4fc8b2009-06-01 13:00:29 -07003372 /*
3373 * r0 = this, r1 = calleeMethod,
3374 * r1 = &ChainingCell,
3375 * r4PC = callsiteDPC,
3376 */
3377 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3378#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003379 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003380#endif
3381 /* Handle exceptions using the interpreter */
3382 genTrap(cUnit, mir->offset, pcrLabel);
3383 break;
3384 }
3385 /* NOP */
3386 case OP_INVOKE_DIRECT_EMPTY: {
3387 return false;
3388 }
3389 case OP_FILLED_NEW_ARRAY:
3390 case OP_FILLED_NEW_ARRAY_RANGE: {
3391 /* Just let the interpreter deal with these */
3392 genInterpSingleStep(cUnit, mir);
3393 break;
3394 }
3395 default:
3396 return true;
3397 }
3398 return false;
3399}
3400
3401static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003402 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003403{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003404 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3405 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3406 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003407
3408 DecodedInstruction *dInsn = &mir->dalvikInsn;
3409 switch (mir->dalvikInsn.opCode) {
3410 /* calleeMethod = this->clazz->vtable[BBBB] */
3411 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3412 case OP_INVOKE_VIRTUAL_QUICK: {
3413 int methodIndex = dInsn->vB;
3414 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3415 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3416 else
3417 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3418
Ben Cheng38329f52009-07-07 14:19:20 -07003419 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3420 retChainingCell,
3421 predChainingCell,
3422 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003423 break;
3424 }
3425 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3426 case OP_INVOKE_SUPER_QUICK:
3427 case OP_INVOKE_SUPER_QUICK_RANGE: {
3428 const Method *calleeMethod =
3429 cUnit->method->clazz->super->vtable[dInsn->vB];
3430
3431 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3432 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3433 else
3434 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3435
3436 /* r0 = calleeMethod */
3437 loadConstant(cUnit, r0, (int) calleeMethod);
3438
Ben Cheng38329f52009-07-07 14:19:20 -07003439 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3440 calleeMethod);
3441 /* Handle exceptions using the interpreter */
3442 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003443 break;
3444 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003445 default:
3446 return true;
3447 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003448 return false;
3449}
3450
3451/*
3452 * NOTE: We assume here that the special native inline routines
3453 * are side-effect free. By making this assumption, we can safely
3454 * re-execute the routine from the interpreter if it decides it
3455 * wants to throw an exception. We still need to EXPORT_PC(), though.
3456 */
3457static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3458{
3459 DecodedInstruction *dInsn = &mir->dalvikInsn;
3460 switch( mir->dalvikInsn.opCode) {
3461 case OP_EXECUTE_INLINE: {
3462 unsigned int i;
3463 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003464 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003465 int operation = dInsn->vB;
3466
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003467 switch (operation) {
3468 case INLINE_EMPTYINLINEMETHOD:
3469 return false; /* Nop */
3470 case INLINE_STRING_LENGTH:
3471 return genInlinedStringLength(cUnit, mir);
3472 case INLINE_MATH_ABS_INT:
3473 return genInlinedAbsInt(cUnit, mir);
3474 case INLINE_MATH_ABS_LONG:
3475 return genInlinedAbsLong(cUnit, mir);
3476 case INLINE_MATH_MIN_INT:
3477 return genInlinedMinMaxInt(cUnit, mir, true);
3478 case INLINE_MATH_MAX_INT:
3479 return genInlinedMinMaxInt(cUnit, mir, false);
3480 case INLINE_STRING_CHARAT:
3481 return genInlinedStringCharAt(cUnit, mir);
3482 case INLINE_MATH_SQRT:
3483 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003484 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003485 else
3486 break; /* Handle with C routine */
3487 case INLINE_MATH_COS:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003488 case INLINE_MATH_SIN:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003489 break; /* Handle with C routine */
3490 case INLINE_MATH_ABS_FLOAT:
3491 return genInlinedAbsFloat(cUnit, mir);
3492 case INLINE_MATH_ABS_DOUBLE:
3493 return genInlinedAbsDouble(cUnit, mir);
3494 case INLINE_STRING_COMPARETO:
3495 case INLINE_STRING_EQUALS:
Bill Buzbee12ba0152009-09-03 14:03:09 -07003496 case INLINE_STRING_INDEXOF_I:
3497 case INLINE_STRING_INDEXOF_II:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003498 break;
3499 default:
3500 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003501 }
3502
3503 /* Materialize pointer to retval & push */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003504 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3505 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3506
Ben Chengba4fc8b2009-06-01 13:00:29 -07003507 /* Push r4 and (just to take up space) r5) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003508 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003509
3510 /* Get code pointer to inline routine */
3511 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3512
3513 /* Export PC */
3514 genExportPC(cUnit, mir, r0, r1 );
3515
3516 /* Load arguments to r0 through r3 as applicable */
3517 for (i=0; i < dInsn->vA; i++) {
3518 loadValue(cUnit, dInsn->arg[i], i);
3519 }
3520 /* Call inline routine */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003521 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003522
3523 /* Strip frame */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003524 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003525
3526 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003527 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003528
Ben Chenge9695e52009-06-16 16:11:47 -07003529 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003530 break;
3531 }
3532 default:
3533 return true;
3534 }
3535 return false;
3536}
3537
3538static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3539{
3540 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3541 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3542 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3543 return false;
3544}
3545
Ben Chengba4fc8b2009-06-01 13:00:29 -07003546/*
3547 * The following are special processing routines that handle transfer of
3548 * controls between compiled code and the interpreter. Certain VM states like
3549 * Dalvik PC and special-purpose registers are reconstructed here.
3550 */
3551
Ben Cheng1efc9c52009-06-08 18:25:27 -07003552/* Chaining cell for code that may need warmup. */
3553static void handleNormalChainingCell(CompilationUnit *cUnit,
3554 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003555{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003556 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3557 jitToInterpEntries.dvmJitToInterpNormal), r0);
3558 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003559 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3560}
3561
3562/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003563 * Chaining cell for instructions that immediately following already translated
3564 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003565 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003566static void handleHotChainingCell(CompilationUnit *cUnit,
3567 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003568{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003569 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3570 jitToInterpEntries.dvmJitToTraceSelect), r0);
3571 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003572 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3573}
3574
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003575#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003576/* Chaining cell for branches that branch back into the same basic block */
3577static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3578 unsigned int offset)
3579{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003580#if defined(WITH_SELF_VERIFICATION)
Jeff Hao97319a82009-08-12 16:57:15 -07003581 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3582 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003583#else
3584 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3585 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3586#endif
Jeff Hao97319a82009-08-12 16:57:15 -07003587 newLIR1(cUnit, THUMB_BLX_R, r0);
3588 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3589}
3590
3591#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003592/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003593static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3594 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003595{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003596 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3597 jitToInterpEntries.dvmJitToTraceSelect), r0);
3598 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003599 addWordData(cUnit, (int) (callee->insns), true);
3600}
3601
Ben Cheng38329f52009-07-07 14:19:20 -07003602/* Chaining cell for monomorphic method invocations. */
3603static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3604{
3605
3606 /* Should not be executed in the initial state */
3607 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3608 /* To be filled: class */
3609 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3610 /* To be filled: method */
3611 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3612 /*
3613 * Rechain count. The initial value of 0 here will trigger chaining upon
3614 * the first invocation of this callsite.
3615 */
3616 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3617}
3618
Ben Chengba4fc8b2009-06-01 13:00:29 -07003619/* Load the Dalvik PC into r0 and jump to the specified target */
3620static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003621 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003622{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003623 ArmLIR **pcrLabel =
3624 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003625 int numElems = cUnit->pcReconstructionList.numUsed;
3626 int i;
3627 for (i = 0; i < numElems; i++) {
3628 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3629 /* r0 = dalvik PC */
3630 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3631 genUnconditionalBranch(cUnit, targetLabel);
3632 }
3633}
3634
Ben Cheng4238ec22009-08-24 16:32:22 -07003635static char *extendedMIROpNames[MIR_OP_LAST - MIR_OP_FIRST] = {
3636 "MIR_OP_PHI",
3637 "MIR_OP_NULL_N_RANGE_UP_CHECK",
3638 "MIR_OP_NULL_N_RANGE_DOWN_CHECK",
3639 "MIR_OP_LOWER_BOUND_CHECK",
3640 "MIR_OP_PUNT",
3641};
3642
3643/*
3644 * vA = arrayReg;
3645 * vB = idxReg;
3646 * vC = endConditionReg;
3647 * arg[0] = maxC
3648 * arg[1] = minC
3649 * arg[2] = loopBranchConditionCode
3650 */
3651static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3652{
3653 DecodedInstruction *dInsn = &mir->dalvikInsn;
3654 const int lenOffset = offsetof(ArrayObject, length);
3655 const int regArray = 0;
3656 const int regIdxEnd = NEXT_REG(regArray);
3657 const int regLength = regArray;
3658 const int maxC = dInsn->arg[0];
3659 const int minC = dInsn->arg[1];
3660
3661 /* regArray <- arrayRef */
3662 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3663 loadValue(cUnit, mir->dalvikInsn.vC, regIdxEnd);
3664 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3665 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3666
3667 /* regLength <- len(arrayRef) */
3668 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3669
3670 int delta = maxC;
3671 /*
3672 * If the loop end condition is ">=" instead of ">", then the largest value
3673 * of the index is "endCondition - 1".
3674 */
3675 if (dInsn->arg[2] == OP_IF_GE) {
3676 delta--;
3677 }
3678
3679 if (delta) {
3680 opRegImm(cUnit, OP_ADD, regIdxEnd, delta, regIdxEnd);
3681 }
3682 /* Punt if "regIdxEnd < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003683 genRegRegCheck(cUnit, ARM_COND_GE, regIdxEnd, regLength, 0,
3684 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003685}
3686
3687/*
3688 * vA = arrayReg;
3689 * vB = idxReg;
3690 * vC = endConditionReg;
3691 * arg[0] = maxC
3692 * arg[1] = minC
3693 * arg[2] = loopBranchConditionCode
3694 */
3695static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3696{
3697 DecodedInstruction *dInsn = &mir->dalvikInsn;
3698 const int lenOffset = offsetof(ArrayObject, length);
3699 const int regArray = 0;
3700 const int regIdxInit = NEXT_REG(regArray);
3701 const int regLength = regArray;
3702 const int maxC = dInsn->arg[0];
3703 const int minC = dInsn->arg[1];
3704
3705 /* regArray <- arrayRef */
3706 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3707 loadValue(cUnit, mir->dalvikInsn.vB, regIdxInit);
3708 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3709 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3710
3711 /* regLength <- len(arrayRef) */
3712 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3713
3714 if (maxC) {
3715 opRegImm(cUnit, OP_ADD, regIdxInit, maxC, regIdxInit);
3716 }
3717
3718 /* Punt if "regIdxInit < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003719 genRegRegCheck(cUnit, ARM_COND_GE, regIdxInit, regLength, 0,
3720 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003721}
3722
3723/*
3724 * vA = idxReg;
3725 * vB = minC;
3726 */
3727static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3728{
3729 DecodedInstruction *dInsn = &mir->dalvikInsn;
3730 const int regIdx = 0;
3731 const int minC = dInsn->vB;
3732
3733 /* regIdx <- initial index value */
3734 loadValue(cUnit, mir->dalvikInsn.vA, regIdx);
3735
3736 /* Punt if "regIdxInit + minC >= 0" is false */
3737 genRegImmCheck(cUnit, ARM_COND_LT, regIdx, -minC, 0,
3738 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3739}
3740
3741/* Extended MIR instructions like PHI */
3742static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3743{
3744 int opOffset = mir->dalvikInsn.opCode - MIR_OP_FIRST;
3745 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3746 false);
3747 strcpy(msg, extendedMIROpNames[opOffset]);
3748 newLIR1(cUnit, ARM_PSEUDO_EXTENDED_MIR, (int) msg);
3749
3750 switch (mir->dalvikInsn.opCode) {
3751 case MIR_OP_PHI: {
3752 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3753 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3754 break;
3755 }
3756 case MIR_OP_NULL_N_RANGE_UP_CHECK: {
3757 genHoistedChecksForCountUpLoop(cUnit, mir);
3758 break;
3759 }
3760 case MIR_OP_NULL_N_RANGE_DOWN_CHECK: {
3761 genHoistedChecksForCountDownLoop(cUnit, mir);
3762 break;
3763 }
3764 case MIR_OP_LOWER_BOUND_CHECK: {
3765 genHoistedLowerBoundCheck(cUnit, mir);
3766 break;
3767 }
3768 case MIR_OP_PUNT: {
3769 genUnconditionalBranch(cUnit,
3770 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3771 break;
3772 }
3773 default:
3774 break;
3775 }
3776}
3777
3778/*
3779 * Create a PC-reconstruction cell for the starting offset of this trace.
3780 * Since the PCR cell is placed near the end of the compiled code which is
3781 * usually out of range for a conditional branch, we put two branches (one
3782 * branch over to the loop body and one layover branch to the actual PCR) at the
3783 * end of the entry block.
3784 */
3785static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3786 ArmLIR *bodyLabel)
3787{
3788 /* Set up the place holder to reconstruct this Dalvik PC */
3789 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3790 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
3791 pcrLabel->operands[0] =
3792 (int) (cUnit->method->insns + entry->startOffset);
3793 pcrLabel->operands[1] = entry->startOffset;
3794 /* Insert the place holder to the growable list */
3795 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3796
3797 /*
3798 * Next, create two branches - one branch over to the loop body and the
3799 * other branch to the PCR cell to punt.
3800 */
3801 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3802 branchToBody->opCode = THUMB_B_UNCOND;
3803 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003804 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07003805 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3806
3807 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3808 branchToPCR->opCode = THUMB_B_UNCOND;
3809 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003810 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003811 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3812}
3813
Ben Chengba4fc8b2009-06-01 13:00:29 -07003814void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3815{
3816 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003817 ArmLIR *labelList =
3818 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003819 GrowableList chainingListByType[CHAINING_CELL_LAST];
3820 int i;
3821
3822 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003823 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003824 */
3825 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3826 dvmInitGrowableList(&chainingListByType[i], 2);
3827 }
3828
3829 BasicBlock **blockList = cUnit->blockList;
3830
Bill Buzbee6e963e12009-06-17 16:56:19 -07003831 if (cUnit->executionCount) {
3832 /*
3833 * Reserve 6 bytes at the beginning of the trace
3834 * +----------------------------+
3835 * | execution count (4 bytes) |
3836 * +----------------------------+
3837 * | chain cell offset (2 bytes)|
3838 * +----------------------------+
3839 * ...and then code to increment the execution
3840 * count:
3841 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3842 * sub r0, #10 @ back up to addr of executionCount
3843 * ldr r1, [r0]
3844 * add r1, #1
3845 * str r1, [r0]
3846 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003847 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3848 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003849 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003850 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003851 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003852 /* Thumb instruction used directly here to ensure correct size */
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003853 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003854 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3855 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3856 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3857 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003858 } else {
3859 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003860 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003861 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003862 cUnit->headerSize = 2;
3863 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003864
Ben Chengba4fc8b2009-06-01 13:00:29 -07003865 /* Handle the content in each basic block */
3866 for (i = 0; i < cUnit->numBlocks; i++) {
3867 blockList[i]->visited = true;
3868 MIR *mir;
3869
3870 labelList[i].operands[0] = blockList[i]->startOffset;
3871
3872 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3873 /*
3874 * Append the label pseudo LIR first. Chaining cells will be handled
3875 * separately afterwards.
3876 */
3877 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3878 }
3879
Ben Cheng4238ec22009-08-24 16:32:22 -07003880 if (blockList[i]->blockType == ENTRY_BLOCK) {
3881 labelList[i].opCode = ARM_PSEUDO_ENTRY_BLOCK;
3882 if (blockList[i]->firstMIRInsn == NULL) {
3883 continue;
3884 } else {
3885 setupLoopEntryBlock(cUnit, blockList[i],
3886 &labelList[blockList[i]->fallThrough->id]);
3887 }
3888 } else if (blockList[i]->blockType == EXIT_BLOCK) {
3889 labelList[i].opCode = ARM_PSEUDO_EXIT_BLOCK;
3890 goto gen_fallthrough;
3891 } else if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003892 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003893 /* Reset the register state */
3894 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003895 } else {
3896 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003897 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003898 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003899 /* handle the codegen later */
3900 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003901 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003902 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003903 case CHAINING_CELL_INVOKE_SINGLETON:
3904 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003905 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003906 labelList[i].operands[0] =
3907 (int) blockList[i]->containingMethod;
3908 /* handle the codegen later */
3909 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003910 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3911 (void *) i);
3912 break;
3913 case CHAINING_CELL_INVOKE_PREDICTED:
3914 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003915 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003916 /* handle the codegen later */
3917 dvmInsertGrowableList(
3918 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3919 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003920 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003921 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003922 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003923 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003924 /* handle the codegen later */
3925 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003926 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003927 (void *) i);
3928 break;
3929 case PC_RECONSTRUCTION:
3930 /* Make sure exception handling block is next */
3931 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003932 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003933 assert (i == cUnit->numBlocks - 2);
3934 handlePCReconstruction(cUnit, &labelList[i+1]);
3935 break;
3936 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003937 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003938 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003939 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3940 jitToInterpEntries.dvmJitToInterpPunt),
3941 r1);
3942 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003943 }
3944 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003945#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003946 case CHAINING_CELL_BACKWARD_BRANCH:
3947 labelList[i].opCode =
3948 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3949 /* handle the codegen later */
3950 dvmInsertGrowableList(
3951 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3952 (void *) i);
3953 break;
3954#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003955 default:
3956 break;
3957 }
3958 continue;
3959 }
Ben Chenge9695e52009-06-16 16:11:47 -07003960
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003961 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003962
Ben Chengba4fc8b2009-06-01 13:00:29 -07003963 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003964 if (mir->dalvikInsn.opCode >= MIR_OP_FIRST) {
3965 handleExtendedMIR(cUnit, mir);
3966 continue;
3967 }
3968
Ben Chengba4fc8b2009-06-01 13:00:29 -07003969 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3970 InstructionFormat dalvikFormat =
3971 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003972 ArmLIR *boundaryLIR =
3973 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Cheng4238ec22009-08-24 16:32:22 -07003974 mir->offset, dalvikOpCode);
3975 if (mir->ssaRep) {
3976 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3977 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3978 }
3979
Ben Chenge9695e52009-06-16 16:11:47 -07003980 /* Remember the first LIR for this block */
3981 if (headLIR == NULL) {
3982 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07003983 /* Set the first boundaryLIR as a scheduling barrier */
3984 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07003985 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003986
Ben Chengba4fc8b2009-06-01 13:00:29 -07003987 bool notHandled;
3988 /*
3989 * Debugging: screen the opcode first to see if it is in the
3990 * do[-not]-compile list
3991 */
3992 bool singleStepMe =
3993 gDvmJit.includeSelectedOp !=
3994 ((gDvmJit.opList[dalvikOpCode >> 3] &
3995 (1 << (dalvikOpCode & 0x7))) !=
3996 0);
Jeff Hao97319a82009-08-12 16:57:15 -07003997#if defined(WITH_SELF_VERIFICATION)
3998 /* Punt on opcodes we can't replay */
3999 if (selfVerificationPuntOps(dalvikOpCode))
4000 singleStepMe = true;
4001#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004002 if (singleStepMe || cUnit->allSingleStep) {
4003 notHandled = false;
4004 genInterpSingleStep(cUnit, mir);
4005 } else {
4006 opcodeCoverage[dalvikOpCode]++;
4007 switch (dalvikFormat) {
4008 case kFmt10t:
4009 case kFmt20t:
4010 case kFmt30t:
4011 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4012 mir, blockList[i], labelList);
4013 break;
4014 case kFmt10x:
4015 notHandled = handleFmt10x(cUnit, mir);
4016 break;
4017 case kFmt11n:
4018 case kFmt31i:
4019 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4020 break;
4021 case kFmt11x:
4022 notHandled = handleFmt11x(cUnit, mir);
4023 break;
4024 case kFmt12x:
4025 notHandled = handleFmt12x(cUnit, mir);
4026 break;
4027 case kFmt20bc:
4028 notHandled = handleFmt20bc(cUnit, mir);
4029 break;
4030 case kFmt21c:
4031 case kFmt31c:
4032 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4033 break;
4034 case kFmt21h:
4035 notHandled = handleFmt21h(cUnit, mir);
4036 break;
4037 case kFmt21s:
4038 notHandled = handleFmt21s(cUnit, mir);
4039 break;
4040 case kFmt21t:
4041 notHandled = handleFmt21t(cUnit, mir, blockList[i],
4042 labelList);
4043 break;
4044 case kFmt22b:
4045 case kFmt22s:
4046 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4047 break;
4048 case kFmt22c:
4049 notHandled = handleFmt22c(cUnit, mir);
4050 break;
4051 case kFmt22cs:
4052 notHandled = handleFmt22cs(cUnit, mir);
4053 break;
4054 case kFmt22t:
4055 notHandled = handleFmt22t(cUnit, mir, blockList[i],
4056 labelList);
4057 break;
4058 case kFmt22x:
4059 case kFmt32x:
4060 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4061 break;
4062 case kFmt23x:
4063 notHandled = handleFmt23x(cUnit, mir);
4064 break;
4065 case kFmt31t:
4066 notHandled = handleFmt31t(cUnit, mir);
4067 break;
4068 case kFmt3rc:
4069 case kFmt35c:
4070 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4071 labelList);
4072 break;
4073 case kFmt3rms:
4074 case kFmt35ms:
4075 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4076 labelList);
4077 break;
4078 case kFmt3inline:
4079 notHandled = handleFmt3inline(cUnit, mir);
4080 break;
4081 case kFmt51l:
4082 notHandled = handleFmt51l(cUnit, mir);
4083 break;
4084 default:
4085 notHandled = true;
4086 break;
4087 }
4088 }
4089 if (notHandled) {
4090 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4091 mir->offset,
4092 dalvikOpCode, getOpcodeName(dalvikOpCode),
4093 dalvikFormat);
4094 dvmAbort();
4095 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004096 }
4097 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004098
4099 if (blockList[i]->blockType == ENTRY_BLOCK) {
4100 dvmCompilerAppendLIR(cUnit,
4101 (LIR *) cUnit->loopAnalysis->branchToBody);
4102 dvmCompilerAppendLIR(cUnit,
4103 (LIR *) cUnit->loopAnalysis->branchToPCR);
4104 }
4105
4106 if (headLIR) {
4107 /*
4108 * Eliminate redundant loads/stores and delay stores into later
4109 * slots
4110 */
4111 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4112 cUnit->lastLIRInsn);
4113 }
4114
4115gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004116 /*
4117 * Check if the block is terminated due to trace length constraint -
4118 * insert an unconditional branch to the chaining cell.
4119 */
4120 if (blockList[i]->needFallThroughBranch) {
4121 genUnconditionalBranch(cUnit,
4122 &labelList[blockList[i]->fallThrough->id]);
4123 }
4124
Ben Chengba4fc8b2009-06-01 13:00:29 -07004125 }
4126
Ben Chenge9695e52009-06-16 16:11:47 -07004127 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07004128 for (i = 0; i < CHAINING_CELL_LAST; i++) {
4129 size_t j;
4130 int *blockIdList = (int *) chainingListByType[i].elemList;
4131
4132 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4133
4134 /* No chaining cells of this type */
4135 if (cUnit->numChainingCells[i] == 0)
4136 continue;
4137
4138 /* Record the first LIR for a new type of chaining cell */
4139 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4140
4141 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4142 int blockId = blockIdList[j];
4143
4144 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004145 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004146
4147 /* Insert the pseudo chaining instruction */
4148 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4149
4150
4151 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07004152 case CHAINING_CELL_NORMAL:
4153 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004154 blockList[blockId]->startOffset);
4155 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004156 case CHAINING_CELL_INVOKE_SINGLETON:
4157 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004158 blockList[blockId]->containingMethod);
4159 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004160 case CHAINING_CELL_INVOKE_PREDICTED:
4161 handleInvokePredictedChainingCell(cUnit);
4162 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07004163 case CHAINING_CELL_HOT:
4164 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004165 blockList[blockId]->startOffset);
4166 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004167#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07004168 case CHAINING_CELL_BACKWARD_BRANCH:
4169 handleBackwardBranchChainingCell(cUnit,
4170 blockList[blockId]->startOffset);
4171 break;
4172#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004173 default:
4174 dvmAbort();
4175 break;
4176 }
4177 }
4178 }
Ben Chenge9695e52009-06-16 16:11:47 -07004179
4180 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004181}
4182
4183/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004184bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004185{
Bill Buzbee716f1202009-07-23 13:22:09 -07004186 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004187
4188 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07004189 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004190 }
4191
4192 switch (work->kind) {
4193 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07004194 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004195 break;
4196 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004197 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07004198 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004199 break;
4200 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07004201 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004202 dvmAbort();
4203 }
4204 return res;
4205}
4206
Ben Chengba4fc8b2009-06-01 13:00:29 -07004207/* Architectural-specific debugging helpers go here */
4208void dvmCompilerArchDump(void)
4209{
4210 /* Print compiled opcode in this VM instance */
4211 int i, start, streak;
4212 char buf[1024];
4213
4214 streak = i = 0;
4215 buf[0] = 0;
4216 while (opcodeCoverage[i] == 0 && i < 256) {
4217 i++;
4218 }
4219 if (i == 256) {
4220 return;
4221 }
4222 for (start = i++, streak = 1; i < 256; i++) {
4223 if (opcodeCoverage[i]) {
4224 streak++;
4225 } else {
4226 if (streak == 1) {
4227 sprintf(buf+strlen(buf), "%x,", start);
4228 } else {
4229 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4230 }
4231 streak = 0;
4232 while (opcodeCoverage[i] == 0 && i < 256) {
4233 i++;
4234 }
4235 if (i < 256) {
4236 streak = 1;
4237 start = i;
4238 }
4239 }
4240 }
4241 if (streak) {
4242 if (streak == 1) {
4243 sprintf(buf+strlen(buf), "%x", start);
4244 } else {
4245 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4246 }
4247 }
4248 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004249 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004250 }
4251}
Ben Chengd7d426a2009-09-22 11:23:36 -07004252
4253/* Common initialization routine for an architecture family */
4254bool dvmCompilerArchInit()
4255{
4256 int i;
4257
4258 for (i = 0; i < ARM_LAST; i++) {
4259 if (EncodingMap[i].opCode != i) {
4260 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4261 EncodingMap[i].name, i, EncodingMap[i].opCode);
4262 dvmAbort();
4263 }
4264 }
4265
4266 return compilerArchVariantInit();
4267}