blob: 8ae22af128826a34f89871f822a6c670d5604904 [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
125 //LOGD("*** HEAP LOAD: Addr: 0x%x Data: 0x%x", addr, data);
126
127 int reg = (heapArgSpace->regMap >> 4) & 0xF;
128 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
129}
130
131static void selfVerificationLoadByte(InterpState* interpState)
132{
133 Thread *self = dvmThreadSelf();
134 ShadowHeap *heapSpacePtr;
135 ShadowSpace *shadowSpace = self->shadowSpace;
136 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
137
138 int addr, data;
139 selfVerificationLoadDecode(heapArgSpace, &addr);
140
141 int maskedAddr = addr & 0xFFFFFFFC;
142 int alignment = addr & 0x3;
143
144 for (heapSpacePtr = shadowSpace->heapSpace;
145 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
146 if (heapSpacePtr->addr == maskedAddr) {
147 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
148 data = *((unsigned char*) addr);
149 break;
150 }
151 }
152
153 if (heapSpacePtr == shadowSpace->heapSpaceTail)
154 data = *((unsigned char*) addr);
155
156 //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
157
158 int reg = (heapArgSpace->regMap >> 4) & 0xF;
159 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
160}
161
162static void selfVerificationLoadHalfword(InterpState* interpState)
163{
164 Thread *self = dvmThreadSelf();
165 ShadowHeap *heapSpacePtr;
166 ShadowSpace *shadowSpace = self->shadowSpace;
167 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
168
169 int addr, data;
170 selfVerificationLoadDecode(heapArgSpace, &addr);
171
172 int maskedAddr = addr & 0xFFFFFFFC;
173 int alignment = addr & 0x2;
174
175 for (heapSpacePtr = shadowSpace->heapSpace;
176 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
177 if (heapSpacePtr->addr == maskedAddr) {
178 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
179 data = *((unsigned short*) addr);
180 break;
181 }
182 }
183
184 if (heapSpacePtr == shadowSpace->heapSpaceTail)
185 data = *((unsigned short*) addr);
186
187 //LOGD("*** HEAP LOAD HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
188
189 int reg = (heapArgSpace->regMap >> 4) & 0xF;
190 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
191}
192
193static void selfVerificationLoadSignedByte(InterpState* interpState)
194{
195 Thread *self = dvmThreadSelf();
196 ShadowHeap* heapSpacePtr;
197 ShadowSpace* shadowSpace = self->shadowSpace;
198 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
199
200 int addr, data;
201 selfVerificationLoadDecode(heapArgSpace, &addr);
202
203 int maskedAddr = addr & 0xFFFFFFFC;
204 int alignment = addr & 0x3;
205
206 for (heapSpacePtr = shadowSpace->heapSpace;
207 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
208 if (heapSpacePtr->addr == maskedAddr) {
209 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
210 data = *((signed char*) addr);
211 break;
212 }
213 }
214
215 if (heapSpacePtr == shadowSpace->heapSpaceTail)
216 data = *((signed char*) addr);
217
218 //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
219
220 int reg = (heapArgSpace->regMap >> 4) & 0xF;
221 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
222}
223
224static void selfVerificationLoadSignedHalfword(InterpState* interpState)
225{
226 Thread *self = dvmThreadSelf();
227 ShadowHeap* heapSpacePtr;
228 ShadowSpace* shadowSpace = self->shadowSpace;
229 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
230
231 int addr, data;
232 selfVerificationLoadDecode(heapArgSpace, &addr);
233
234 int maskedAddr = addr & 0xFFFFFFFC;
235 int alignment = addr & 0x2;
236
237 for (heapSpacePtr = shadowSpace->heapSpace;
238 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
239 if (heapSpacePtr->addr == maskedAddr) {
240 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
241 data = *((signed short*) addr);
242 break;
243 }
244 }
245
246 if (heapSpacePtr == shadowSpace->heapSpaceTail)
247 data = *((signed short*) addr);
248
249 //LOGD("*** HEAP LOAD SIGNED HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
250
251 int reg = (heapArgSpace->regMap >> 4) & 0xF;
252 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
253}
254
255static void selfVerificationLoadDoubleword(InterpState* interpState)
256{
257 Thread *self = dvmThreadSelf();
258 ShadowHeap* heapSpacePtr;
259 ShadowSpace* shadowSpace = self->shadowSpace;
260 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
261
262 int addr;
263 selfVerificationLoadDecode(heapArgSpace, &addr);
264
265 int addr2 = addr+4;
266 unsigned int data = *((unsigned int*) addr);
267 unsigned int data2 = *((unsigned int*) addr2);
268
269 for (heapSpacePtr = shadowSpace->heapSpace;
270 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
271 if (heapSpacePtr->addr == addr) {
272 data = heapSpacePtr->data;
273 } else if (heapSpacePtr->addr == addr2) {
274 data2 = heapSpacePtr->data;
275 }
276 }
277
278 //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
279 // addr, data, data2);
280
281 int reg = (heapArgSpace->regMap >> 4) & 0xF;
282 int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
283 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
284 selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
285}
286
287/* Decode contents of heapArgSpace to determine arguments to store. */
288static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
289 int* value, int reg)
290{
291 switch (reg) {
292 case 0:
293 *value = heapArgSpace->r0;
294 break;
295 case 1:
296 *value = heapArgSpace->r1;
297 break;
298 case 2:
299 *value = heapArgSpace->r2;
300 break;
301 case 3:
302 *value = heapArgSpace->r3;
303 break;
304 default:
305 LOGE("ERROR: bad reg passed to selfVerificationStoreDecode: %d",
306 reg);
307 break;
308 }
309}
310
311static void selfVerificationStore(InterpState* interpState)
312{
313 Thread *self = dvmThreadSelf();
314 ShadowHeap *heapSpacePtr;
315 ShadowSpace *shadowSpace = self->shadowSpace;
316 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
317
318 int addr, data;
319 int reg0 = heapArgSpace->regMap & 0xF;
320 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
321 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
322 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
323
324 //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
325
326 for (heapSpacePtr = shadowSpace->heapSpace;
327 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
328 if (heapSpacePtr->addr == addr) break;
329 }
330
331 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
332 heapSpacePtr->addr = addr;
333 shadowSpace->heapSpaceTail++;
334 }
335
336 heapSpacePtr->data = data;
337}
338
339static void selfVerificationStoreByte(InterpState* interpState)
340{
341 Thread *self = dvmThreadSelf();
342 ShadowHeap *heapSpacePtr;
343 ShadowSpace *shadowSpace = self->shadowSpace;
344 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
345
346 int addr, data;
347 int reg0 = heapArgSpace->regMap & 0xF;
348 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
349 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
350 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
351
352 int maskedAddr = addr & 0xFFFFFFFC;
353 int alignment = addr & 0x3;
354
355 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
356
357 for (heapSpacePtr = shadowSpace->heapSpace;
358 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
359 if (heapSpacePtr->addr == maskedAddr) break;
360 }
361
362 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
363 heapSpacePtr->addr = maskedAddr;
364 heapSpacePtr->data = *((unsigned int*) maskedAddr);
365 shadowSpace->heapSpaceTail++;
366 }
367
368 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
369 *((unsigned char*) addr) = (char) data;
370
371 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
372 // addr, heapSpacePtr->data);
373}
374
375static void selfVerificationStoreHalfword(InterpState* interpState)
376{
377 Thread *self = dvmThreadSelf();
378 ShadowHeap *heapSpacePtr;
379 ShadowSpace *shadowSpace = self->shadowSpace;
380 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
381
382 int addr, data;
383 int reg0 = heapArgSpace->regMap & 0xF;
384 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
385 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
386 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
387
388 int maskedAddr = addr & 0xFFFFFFFC;
389 int alignment = addr & 0x2;
390
391 //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
392
393 for (heapSpacePtr = shadowSpace->heapSpace;
394 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
395 if (heapSpacePtr->addr == maskedAddr) break;
396 }
397
398 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
399 heapSpacePtr->addr = maskedAddr;
400 heapSpacePtr->data = *((unsigned int*) maskedAddr);
401 shadowSpace->heapSpaceTail++;
402 }
403
404 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
405 *((unsigned short*) addr) = (short) data;
406
407 //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Final Data: 0x%x",
408 // addr, heapSpacePtr->data);
409}
410
411static void selfVerificationStoreDoubleword(InterpState* interpState)
412{
413 Thread *self = dvmThreadSelf();
414 ShadowHeap *heapSpacePtr;
415 ShadowSpace *shadowSpace = self->shadowSpace;
416 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
417
418 int addr, data, data2;
419 int reg0 = heapArgSpace->regMap & 0xF;
420 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
421 int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
422 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
423 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
424 selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
425
426 int addr2 = addr+4;
427 bool store1 = false, store2 = false;
428
429 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
430 // addr, data, data2);
431
432 for (heapSpacePtr = shadowSpace->heapSpace;
433 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
434 if (heapSpacePtr->addr == addr) {
435 heapSpacePtr->data = data;
436 store1 = true;
437 } else if (heapSpacePtr->addr == addr2) {
438 heapSpacePtr->data = data2;
439 store2 = true;
440 }
441 }
442
443 if (!store1) {
444 shadowSpace->heapSpaceTail->addr = addr;
445 shadowSpace->heapSpaceTail->data = data;
446 shadowSpace->heapSpaceTail++;
447 }
448 if (!store2) {
449 shadowSpace->heapSpaceTail->addr = addr2;
450 shadowSpace->heapSpaceTail->data = data2;
451 shadowSpace->heapSpaceTail++;
452 }
453}
454
455/* Common wrapper function for all memory operations */
456static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
457 void* funct)
458{
459 int regMask = (1 << r4PC) | (1 << r3) | (1 << r2) | (1 << r1) | (1 << r0);
460
461 /* r7 <- InterpState->heapArgSpace */
462 loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
463 newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
464
465 /* Save out values to heapArgSpace */
466 loadConstant(cUnit, r4PC, regMap);
467 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
468
469 /* Pass interpState pointer to function */
470 newLIR2(cUnit, THUMB_MOV_RR, r0, rGLUE);
471
472 /* Set function pointer and branch */
473 loadConstant(cUnit, r1, (int) funct);
474 newLIR1(cUnit, THUMB_BLX_R, r1);
475
476 /* r7 <- InterpState->heapArgSpace */
477 loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
478 newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
479
480 /* Restore register state */
481 newLIR2(cUnit, THUMB_LDMIA, r7, regMask);
482}
483#endif
484
Ben Chengba4fc8b2009-06-01 13:00:29 -0700485/*
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700486 * Set up the proper fields in the resource mask
487 */
488static void setupResourceMasks(ArmLIR *lir)
489{
490 int opCode = lir->opCode;
491 int flags;
492
493 if (opCode <= 0) {
494 lir->useMask = lir->defMask = 0;
495 return;
496 }
497
498 flags = EncodingMap[lir->opCode].flags;
499
500 /* Set up the mask for resources that are updated */
501 if (flags & IS_BRANCH) {
502 lir->defMask |= ENCODE_REG_PC;
503 }
504
505 if (flags & REG_DEF0) {
506 lir->defMask |= ENCODE_GP_REG(lir->operands[0]);
507 }
508
509 if (flags & REG_DEF1) {
510 lir->defMask |= ENCODE_GP_REG(lir->operands[1]);
511 }
512
513 if (flags & REG_DEF_SP) {
514 lir->defMask |= ENCODE_REG_SP;
515 }
516
517 if (flags & REG_DEF_LIST0) {
518 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
519 }
520
521 if (flags & REG_DEF_LIST1) {
522 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
523 }
524
525 if (flags & SETS_CCODES) {
526 lir->defMask |= ENCODE_CCODE;
527 }
528
529 /* Conservatively treat the IT block */
530 if (flags & IS_IT) {
531 lir->defMask = -1;
532 }
533
534 /* Set up the mask for resources that are used */
535 if (flags & IS_BRANCH) {
536 lir->useMask |= ENCODE_REG_PC;
537 }
538
539 if (flags & (REG_USE0 | REG_USE1 | REG_USE2)) {
540 int i;
541
542 for (i = 0; i < 3; i++) {
543 if (flags & (1 << (kRegUse0 + i))) {
544 lir->useMask |= ENCODE_GP_REG(lir->operands[i]);
545 }
546 }
547 }
548
549 if (flags & REG_USE_PC) {
550 lir->useMask |= ENCODE_REG_PC;
551 }
552
553 if (flags & REG_USE_SP) {
554 lir->useMask |= ENCODE_REG_SP;
555 }
556
557 if (flags & REG_USE_LIST0) {
558 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
559 }
560
561 if (flags & REG_USE_LIST1) {
562 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
563 }
564
565 if (flags & USES_CCODES) {
566 lir->useMask |= ENCODE_CCODE;
567 }
568}
569
570/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700571 * The following are building blocks to construct low-level IRs with 0 - 4
Ben Chengba4fc8b2009-06-01 13:00:29 -0700572 * operands.
573 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700574static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700575{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700576 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700577 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700578 insn->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700579 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700580 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
581 return insn;
582}
583
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700584static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700585 int dest)
586{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700587 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700588 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700589 insn->opCode = opCode;
590 insn->operands[0] = dest;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700591 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700592 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
593 return insn;
594}
595
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700596static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700597 int dest, int src1)
598{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700599 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700600 assert(isPseudoOpCode(opCode) ||
601 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700602 insn->opCode = opCode;
603 insn->operands[0] = dest;
604 insn->operands[1] = src1;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700605 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700606 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
607 return insn;
608}
609
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700610static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700611 int dest, int src1, int src2)
612{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700613 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700614 assert(isPseudoOpCode(opCode) ||
615 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700616 insn->opCode = opCode;
617 insn->operands[0] = dest;
618 insn->operands[1] = src1;
619 insn->operands[2] = src2;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700620 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700621 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
622 return insn;
623}
624
Bill Buzbee270c1d62009-08-13 16:58:07 -0700625static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
626 int dest, int src1, int src2, int info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700627{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700628 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
629 assert(isPseudoOpCode(opCode) ||
630 (EncodingMap[opCode].flags & IS_QUAD_OP));
631 insn->opCode = opCode;
632 insn->operands[0] = dest;
633 insn->operands[1] = src1;
634 insn->operands[2] = src2;
635 insn->operands[3] = info;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700636 setupResourceMasks(insn);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700637 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
638 return insn;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700639}
640
Ben Chengba4fc8b2009-06-01 13:00:29 -0700641/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700642 * If the next instruction is a move-result or move-result-long,
643 * return the target Dalvik instruction and convert the next to a
644 * nop. Otherwise, return -1. Used to optimize method inlining.
645 */
646static int inlinedTarget(MIR *mir)
647{
648 if (mir->next &&
649 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
650 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT) ||
651 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE))) {
652 mir->next->dalvikInsn.opCode = OP_NOP;
653 return mir->next->dalvikInsn.vA;
654 } else {
655 return -1;
656 }
657}
658
659
660
661/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700662 * The following are building blocks to insert constants into the pool or
663 * instruction streams.
664 */
665
666/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700667static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700668{
669 /* Add the constant to the literal pool */
670 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700671 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700672 newValue->operands[0] = value;
673 newValue->generic.next = cUnit->wordList;
674 cUnit->wordList = (LIR *) newValue;
675 return newValue;
676 } else {
677 /* Add the constant in the middle of code stream */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700678 newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
679 newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700680 }
681 return NULL;
682}
683
684/*
685 * Search the existing constants in the literal pool for an exact or close match
686 * within specified delta (greater or equal to 0).
687 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700688static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700689 unsigned int delta)
690{
691 LIR *dataTarget = cUnit->wordList;
692 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700693 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700694 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700695 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700696 dataTarget = dataTarget->next;
697 }
698 return NULL;
699}
700
Ben Chengba4fc8b2009-06-01 13:00:29 -0700701/* Perform the actual operation for OP_RETURN_* */
702static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
703{
704 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
705#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700706 gDvmJit.returnOp++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700707#endif
708 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700709 /* Insert branch, but defer setting of target */
710 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700711 /* Set up the place holder to reconstruct this Dalvik PC */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700712 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
713 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700714 pcrLabel->operands[0] = dPC;
715 pcrLabel->operands[1] = mir->offset;
716 /* Insert the place holder to the growable list */
717 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
718 /* Branch to the PC reconstruction code */
719 branch->generic.target = (LIR *) pcrLabel;
720}
721
Ben Chengba4fc8b2009-06-01 13:00:29 -0700722/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700723static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
724 ArmLIR *branch,
725 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700726{
727 /* Set up the place holder to reconstruct this Dalvik PC */
728 if (pcrLabel == NULL) {
729 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700730 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
731 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700732 pcrLabel->operands[0] = dPC;
733 pcrLabel->operands[1] = dOffset;
734 /* Insert the place holder to the growable list */
735 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
736 }
737 /* Branch to the PC reconstruction code */
738 branch->generic.target = (LIR *) pcrLabel;
739 return pcrLabel;
740}
741
Ben Chengba4fc8b2009-06-01 13:00:29 -0700742
743/*
744 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
745 * satisfies.
746 */
Ben Cheng0fd31e42009-09-03 14:40:16 -0700747static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
748 ArmConditionCode cond,
749 int reg1, int reg2, int dOffset,
750 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700751{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700752 ArmLIR *res;
753 res = opRegReg(cUnit, OP_CMP, reg1, reg2);
754 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
755 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
756 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700757}
758
Ben Chenge9695e52009-06-16 16:11:47 -0700759/*
760 * Perform null-check on a register. vReg is the Dalvik register being checked,
761 * and mReg is the machine register holding the actual value. If internal state
762 * indicates that vReg has been checked before the check request is ignored.
763 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700764static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
765 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700766{
Ben Chenge9695e52009-06-16 16:11:47 -0700767 /* This particular Dalvik register has been null-checked */
768 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
769 return pcrLabel;
770 }
771 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
772 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
773}
774
775/*
776 * Perform zero-check on a register. Similar to genNullCheck but the value being
777 * checked does not have a corresponding Dalvik register.
778 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700779static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
780 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -0700781{
782 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700783}
784
785/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700786static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
787 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700788{
Ben Cheng0fd31e42009-09-03 14:40:16 -0700789 return genRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700790 pcrLabel);
791}
792
793/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700794static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
795 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700796{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700797 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700798 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
799}
800
801/* Load a wide field from an object instance */
802static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
803{
804 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700805 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700806
Ben Chenge9695e52009-06-16 16:11:47 -0700807 /* Allocate reg0..reg3 into physical registers r0..r3 */
808
809 /* See if vB is in a native register. If so, reuse it. */
810 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
811 /* Ping reg3 to the other register of the same pair containing reg2 */
812 reg3 = reg2 ^ 0x1;
813 /*
814 * Ping reg0 to the first register of the alternate register pair
815 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700816 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700817 reg1 = NEXT_REG(reg0);
818
819 loadValue(cUnit, dInsn->vB, reg2);
820 loadConstant(cUnit, reg3, fieldOffset);
821 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700822 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700823#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700824 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700825#else
826 int regMap = reg1 << 8 | reg0 << 4 | reg2;
827 selfVerificationMemOpWrapper(cUnit, regMap,
828 &selfVerificationLoadDoubleword);
Jeff Hao97319a82009-08-12 16:57:15 -0700829#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700830 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700831}
832
833/* Store a wide field to an object instance */
834static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
835{
836 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700837 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700838
Ben Chenge9695e52009-06-16 16:11:47 -0700839 /* Allocate reg0..reg3 into physical registers r0..r3 */
840
841 /* See if vB is in a native register. If so, reuse it. */
842 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
843 /* Ping reg3 to the other register of the same pair containing reg2 */
844 reg3 = reg2 ^ 0x1;
845 /*
846 * Ping reg0 to the first register of the alternate register pair
847 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700848 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700849 reg1 = NEXT_REG(reg0);
850
851
852 loadValue(cUnit, dInsn->vB, reg2);
853 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
854 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
855 loadConstant(cUnit, reg3, fieldOffset);
856 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700857 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700858#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700859 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700860#else
861 int regMap = reg1 << 8 | reg0 << 4 | reg2;
862 selfVerificationMemOpWrapper(cUnit, regMap,
863 &selfVerificationStoreDoubleword);
864#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700865}
866
867/*
868 * Load a field from an object instance
869 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700870 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700871static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700872 int fieldOffset)
873{
874 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700875 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700876
Ben Chenge9695e52009-06-16 16:11:47 -0700877 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
878 reg1 = NEXT_REG(reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700879 loadValue(cUnit, dInsn->vB, reg0);
Jeff Hao97319a82009-08-12 16:57:15 -0700880#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700881 loadBaseDisp(cUnit, mir, reg0, fieldOffset, reg1, size, true, dInsn->vB);
Jeff Hao97319a82009-08-12 16:57:15 -0700882#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700883 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700884 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700885 loadConstant(cUnit, reg1, fieldOffset);
886 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700887
Bill Buzbee270c1d62009-08-13 16:58:07 -0700888 int regMap = reg1 << 4 | reg0;
Jeff Hao97319a82009-08-12 16:57:15 -0700889 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
Jeff Hao97319a82009-08-12 16:57:15 -0700890#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700891 storeValue(cUnit, reg1, dInsn->vA, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700892}
893
894/*
895 * Store a field to an object instance
896 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700897 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700898static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700899 int fieldOffset)
900{
901 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700902 int reg0, reg1, reg2;
903
904 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
905 reg1 = NEXT_REG(reg0);
906 reg2 = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700907
Ben Chenge9695e52009-06-16 16:11:47 -0700908 loadValue(cUnit, dInsn->vB, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700909 loadValue(cUnit, dInsn->vA, reg2);
910 updateLiveRegister(cUnit, dInsn->vA, reg2);
911 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700912#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700913 storeBaseDisp(cUnit, reg0, fieldOffset, reg2, size, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700914#else
915 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700916 loadConstant(cUnit, reg1, fieldOffset);
917 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700918
919 int regMap = reg2 << 4 | reg0;
920 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
921
Bill Buzbee270c1d62009-08-13 16:58:07 -0700922 opRegReg(cUnit, OP_SUB, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700923#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700924}
925
926
Ben Chengba4fc8b2009-06-01 13:00:29 -0700927/*
928 * Generate array load
929 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700930 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700931static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700932 int vArray, int vIndex, int vDest, int scale)
933{
934 int lenOffset = offsetof(ArrayObject, length);
935 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700936 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700937
Ben Chenge9695e52009-06-16 16:11:47 -0700938 reg0 = selectFirstRegister(cUnit, vArray, false);
939 reg1 = NEXT_REG(reg0);
940 reg2 = NEXT_REG(reg1);
941 reg3 = NEXT_REG(reg2);
942
943 loadValue(cUnit, vArray, reg2);
944 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700945
946 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -0700947 ArmLIR * pcrLabel = NULL;
948
949 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
950 pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
951 }
952
953 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
954 /* Get len */
955 loadWordDisp(cUnit, reg2, lenOffset, reg0);
956 /* reg2 -> array data */
957 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
958 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
959 } else {
960 /* reg2 -> array data */
961 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
962 }
Jeff Hao97319a82009-08-12 16:57:15 -0700963#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700964 if ((size == LONG) || (size == DOUBLE)) {
965 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
966 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
967 loadBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
968 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
969 loadBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
Ben Chenge9695e52009-06-16 16:11:47 -0700970 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700971 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700972 loadBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
Ben Chenge9695e52009-06-16 16:11:47 -0700973 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700974 }
Jeff Hao97319a82009-08-12 16:57:15 -0700975#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700976 //TODO: probably want to move this into loadBaseIndexed
977 void *funct = NULL;
978 switch(size) {
979 case LONG:
980 case DOUBLE:
Jeff Hao97319a82009-08-12 16:57:15 -0700981 funct = (void*) &selfVerificationLoadDoubleword;
982 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700983 case WORD:
Jeff Hao97319a82009-08-12 16:57:15 -0700984 funct = (void*) &selfVerificationLoad;
985 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700986 case UNSIGNED_HALF:
987 funct = (void*) &selfVerificationLoadHalfword;
988 break;
989 case SIGNED_HALF:
990 funct = (void*) &selfVerificationLoadSignedHalfword;
991 break;
992 case UNSIGNED_BYTE:
993 funct = (void*) &selfVerificationLoadByte;
994 break;
995 case SIGNED_BYTE:
996 funct = (void*) &selfVerificationLoadSignedByte;
997 break;
998 default:
999 assert(0);
1000 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -07001001 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001002 /* Combine address and index */
1003 if (scale)
1004 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1005 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001006
1007 int regMap = reg1 << 8 | reg0 << 4 | reg2;
1008 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1009
Bill Buzbee270c1d62009-08-13 16:58:07 -07001010 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001011
Bill Buzbee270c1d62009-08-13 16:58:07 -07001012 if ((size == LONG) || (size == DOUBLE))
Jeff Hao97319a82009-08-12 16:57:15 -07001013 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
1014 else
1015 storeValue(cUnit, reg0, vDest, reg3);
1016#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001017}
1018
Ben Chengba4fc8b2009-06-01 13:00:29 -07001019/*
1020 * Generate array store
1021 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001022 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001023static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001024 int vArray, int vIndex, int vSrc, int scale)
1025{
1026 int lenOffset = offsetof(ArrayObject, length);
1027 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -07001028 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001029
Ben Chenge9695e52009-06-16 16:11:47 -07001030 reg0 = selectFirstRegister(cUnit, vArray, false);
1031 reg1 = NEXT_REG(reg0);
1032 reg2 = NEXT_REG(reg1);
1033 reg3 = NEXT_REG(reg2);
1034
1035 loadValue(cUnit, vArray, reg2);
1036 loadValue(cUnit, vIndex, reg3);
1037
Ben Cheng1efc9c52009-06-08 18:25:27 -07001038 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001039 ArmLIR * pcrLabel = NULL;
1040
1041 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
1042 pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
1043 }
1044
1045 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
1046 /* Get len */
1047 loadWordDisp(cUnit, reg2, lenOffset, reg0);
1048 /* reg2 -> array data */
1049 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1050 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
1051 } else {
1052 /* reg2 -> array data */
1053 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
1054 }
1055
Ben Chenge9695e52009-06-16 16:11:47 -07001056 /* at this point, reg2 points to array, reg3 is unscaled index */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001057#if !defined(WITH_SELF_VERIFICATION)
1058 if ((size == LONG) || (size == DOUBLE)) {
1059 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
1060 loadValuePair(cUnit, vSrc, reg0, reg1);
1061 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
1062 if (scale)
1063 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1064 storeBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
1065 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
1066 storeBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
1067 } else {
1068 loadValue(cUnit, vSrc, reg0);
1069 updateLiveRegister(cUnit, vSrc, reg0);
1070 storeBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
1071 }
1072#else
1073 //TODO: probably want to move this into storeBaseIndexed
1074 void *funct = NULL;
1075 switch(size) {
1076 case LONG:
1077 case DOUBLE:
1078 funct = (void*) &selfVerificationStoreDoubleword;
1079 break;
1080 case WORD:
1081 funct = (void*) &selfVerificationStore;
1082 break;
1083 case SIGNED_HALF:
1084 case UNSIGNED_HALF:
1085 funct = (void*) &selfVerificationStoreHalfword;
1086 break;
1087 case SIGNED_BYTE:
1088 case UNSIGNED_BYTE:
1089 funct = (void*) &selfVerificationStoreByte;
1090 break;
1091 default:
1092 assert(0);
1093 dvmAbort();
1094 }
1095
1096 /* Combine address and index */
1097 if ((size == LONG) || (size == DOUBLE)) {
Ben Chenge9695e52009-06-16 16:11:47 -07001098 loadValuePair(cUnit, vSrc, reg0, reg1);
1099 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001100 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001101 loadValue(cUnit, vSrc, reg0);
1102 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001103 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001104 if (scale)
1105 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1106 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001107
1108 int regMap = reg1 << 8 | reg0 << 4 | reg2;
1109 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1110
Bill Buzbee270c1d62009-08-13 16:58:07 -07001111 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001112#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001113}
1114
1115static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1116 int vSrc1, int vShift)
1117{
Ben Chenge9695e52009-06-16 16:11:47 -07001118 /*
1119 * Don't mess with the regsiters here as there is a particular calling
1120 * convention to the out-of-line handler.
1121 */
1122 loadValue(cUnit, vShift, r2);
1123 loadValuePair(cUnit, vSrc1, r0, r1);
1124 switch( mir->dalvikInsn.opCode) {
1125 case OP_SHL_LONG:
1126 case OP_SHL_LONG_2ADDR:
1127 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1128 break;
1129 case OP_SHR_LONG:
1130 case OP_SHR_LONG_2ADDR:
1131 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1132 break;
1133 case OP_USHR_LONG:
1134 case OP_USHR_LONG_2ADDR:
1135 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1136 break;
1137 default:
1138 return true;
1139 }
1140 storeValuePair(cUnit, r0, r1, vDest, r2);
1141 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001142}
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001143bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1144 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001145{
Ben Chenge9695e52009-06-16 16:11:47 -07001146 /*
1147 * Don't optimize the regsiter usage here as they are governed by the EABI
1148 * calling convention.
1149 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001150 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001151 int reg0, reg1;
1152
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153 /* TODO: use a proper include file to define these */
1154 float __aeabi_fadd(float a, float b);
1155 float __aeabi_fsub(float a, float b);
1156 float __aeabi_fdiv(float a, float b);
1157 float __aeabi_fmul(float a, float b);
1158 float fmodf(float a, float b);
1159
Ben Chenge9695e52009-06-16 16:11:47 -07001160 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1161 reg1 = NEXT_REG(reg0);
1162
Ben Chengba4fc8b2009-06-01 13:00:29 -07001163 switch (mir->dalvikInsn.opCode) {
1164 case OP_ADD_FLOAT_2ADDR:
1165 case OP_ADD_FLOAT:
1166 funct = (void*) __aeabi_fadd;
1167 break;
1168 case OP_SUB_FLOAT_2ADDR:
1169 case OP_SUB_FLOAT:
1170 funct = (void*) __aeabi_fsub;
1171 break;
1172 case OP_DIV_FLOAT_2ADDR:
1173 case OP_DIV_FLOAT:
1174 funct = (void*) __aeabi_fdiv;
1175 break;
1176 case OP_MUL_FLOAT_2ADDR:
1177 case OP_MUL_FLOAT:
1178 funct = (void*) __aeabi_fmul;
1179 break;
1180 case OP_REM_FLOAT_2ADDR:
1181 case OP_REM_FLOAT:
1182 funct = (void*) fmodf;
1183 break;
1184 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -07001185 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001186 opRegImm(cUnit, OP_ADD, reg0, 0x80000000, reg1);
Ben Chenge9695e52009-06-16 16:11:47 -07001187 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001188 return false;
1189 }
1190 default:
1191 return true;
1192 }
1193 loadConstant(cUnit, r2, (int)funct);
1194 loadValue(cUnit, vSrc1, r0);
1195 loadValue(cUnit, vSrc2, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001196 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001197 storeValue(cUnit, r0, vDest, r1);
1198 return false;
1199}
1200
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001201bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1202 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001203{
1204 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001205 int reg0, reg1, reg2;
1206
Ben Chengba4fc8b2009-06-01 13:00:29 -07001207 /* TODO: use a proper include file to define these */
1208 double __aeabi_dadd(double a, double b);
1209 double __aeabi_dsub(double a, double b);
1210 double __aeabi_ddiv(double a, double b);
1211 double __aeabi_dmul(double a, double b);
1212 double fmod(double a, double b);
1213
Ben Chenge9695e52009-06-16 16:11:47 -07001214 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1215 reg1 = NEXT_REG(reg0);
1216 reg2 = NEXT_REG(reg1);
1217
Ben Chengba4fc8b2009-06-01 13:00:29 -07001218 switch (mir->dalvikInsn.opCode) {
1219 case OP_ADD_DOUBLE_2ADDR:
1220 case OP_ADD_DOUBLE:
1221 funct = (void*) __aeabi_dadd;
1222 break;
1223 case OP_SUB_DOUBLE_2ADDR:
1224 case OP_SUB_DOUBLE:
1225 funct = (void*) __aeabi_dsub;
1226 break;
1227 case OP_DIV_DOUBLE_2ADDR:
1228 case OP_DIV_DOUBLE:
1229 funct = (void*) __aeabi_ddiv;
1230 break;
1231 case OP_MUL_DOUBLE_2ADDR:
1232 case OP_MUL_DOUBLE:
1233 funct = (void*) __aeabi_dmul;
1234 break;
1235 case OP_REM_DOUBLE_2ADDR:
1236 case OP_REM_DOUBLE:
1237 funct = (void*) fmod;
1238 break;
1239 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001240 loadValuePair(cUnit, vSrc2, reg0, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001241 opRegImm(cUnit, OP_ADD, reg1, 0x80000000, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001242 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001243 return false;
1244 }
1245 default:
1246 return true;
1247 }
Ben Chenge9695e52009-06-16 16:11:47 -07001248 /*
1249 * Don't optimize the regsiter usage here as they are governed by the EABI
1250 * calling convention.
1251 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001252 loadConstant(cUnit, r4PC, (int)funct);
1253 loadValuePair(cUnit, vSrc1, r0, r1);
1254 loadValuePair(cUnit, vSrc2, r2, r3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001255 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001256 storeValuePair(cUnit, r0, r1, vDest, r2);
1257 return false;
1258}
1259
1260static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1261 int vSrc1, int vSrc2)
1262{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001263 OpKind firstOp = OP_BKPT;
1264 OpKind secondOp = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001265 bool callOut = false;
1266 void *callTgt;
1267 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -07001268 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001269 /* TODO - find proper .h file to declare these */
1270 long long __aeabi_ldivmod(long long op1, long long op2);
1271
1272 switch (mir->dalvikInsn.opCode) {
1273 case OP_NOT_LONG:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001274 firstOp = OP_MVN;
1275 secondOp = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001276 break;
1277 case OP_ADD_LONG:
1278 case OP_ADD_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001279 firstOp = OP_ADD;
1280 secondOp = OP_ADC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001281 break;
1282 case OP_SUB_LONG:
1283 case OP_SUB_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001284 firstOp = OP_SUB;
1285 secondOp = OP_SBC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001286 break;
1287 case OP_MUL_LONG:
1288 case OP_MUL_LONG_2ADDR:
1289 loadValuePair(cUnit, vSrc1, r0, r1);
1290 loadValuePair(cUnit, vSrc2, r2, r3);
1291 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
1292 storeValuePair(cUnit, r0, r1, vDest, r2);
1293 return false;
1294 break;
1295 case OP_DIV_LONG:
1296 case OP_DIV_LONG_2ADDR:
1297 callOut = true;
1298 retReg = r0;
1299 callTgt = (void*)__aeabi_ldivmod;
1300 break;
1301 /* NOTE - result is in r2/r3 instead of r0/r1 */
1302 case OP_REM_LONG:
1303 case OP_REM_LONG_2ADDR:
1304 callOut = true;
1305 callTgt = (void*)__aeabi_ldivmod;
1306 retReg = r2;
1307 break;
1308 case OP_AND_LONG:
1309 case OP_AND_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001310 firstOp = OP_AND;
1311 secondOp = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001312 break;
1313 case OP_OR_LONG:
1314 case OP_OR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001315 firstOp = OP_OR;
1316 secondOp = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001317 break;
1318 case OP_XOR_LONG:
1319 case OP_XOR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001320 firstOp = OP_XOR;
1321 secondOp = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001322 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001323 case OP_NEG_LONG: {
1324 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1325 reg1 = NEXT_REG(reg0);
1326 reg2 = NEXT_REG(reg1);
1327 reg3 = NEXT_REG(reg2);
1328
1329 loadValuePair(cUnit, vSrc2, reg0, reg1);
1330 loadConstant(cUnit, reg3, 0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001331 opRegRegReg(cUnit, OP_SUB, reg2, reg3, reg0);
1332 opRegReg(cUnit, OP_SBC, reg3, reg1);
Ben Cheng38329f52009-07-07 14:19:20 -07001333 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001334 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001335 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001336 default:
1337 LOGE("Invalid long arith op");
1338 dvmAbort();
1339 }
1340 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001341 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1342 reg1 = NEXT_REG(reg0);
1343 reg2 = NEXT_REG(reg1);
1344 reg3 = NEXT_REG(reg2);
1345
1346 loadValuePair(cUnit, vSrc1, reg0, reg1);
1347 loadValuePair(cUnit, vSrc2, reg2, reg3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001348 opRegReg(cUnit, firstOp, reg0, reg2);
1349 opRegReg(cUnit, secondOp, reg1, reg3);
1350 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001351 /*
Bill Buzbee270c1d62009-08-13 16:58:07 -07001352 * Don't optimize the register usage here as they are governed by the EABI
Ben Chenge9695e52009-06-16 16:11:47 -07001353 * calling convention.
1354 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001355 } else {
1356 loadValuePair(cUnit, vSrc2, r2, r3);
1357 loadConstant(cUnit, r4PC, (int) callTgt);
1358 loadValuePair(cUnit, vSrc1, r0, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001359 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001360 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1361 }
1362 return false;
1363}
1364
1365static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1366 int vSrc1, int vSrc2)
1367{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001368 OpKind op = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001369 bool callOut = false;
1370 bool checkZero = false;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001371 bool threeOperand = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001372 int retReg = r0;
1373 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -07001374 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001375
1376 /* TODO - find proper .h file to declare these */
1377 int __aeabi_idivmod(int op1, int op2);
1378 int __aeabi_idiv(int op1, int op2);
1379
1380 switch (mir->dalvikInsn.opCode) {
1381 case OP_NEG_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001382 op = OP_NEG;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001383 break;
1384 case OP_NOT_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001385 op = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001386 break;
1387 case OP_ADD_INT:
1388 case OP_ADD_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001389 op = OP_ADD;
1390 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001391 break;
1392 case OP_SUB_INT:
1393 case OP_SUB_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001394 op = OP_SUB;
1395 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001396 break;
1397 case OP_MUL_INT:
1398 case OP_MUL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001399 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001400 break;
1401 case OP_DIV_INT:
1402 case OP_DIV_INT_2ADDR:
1403 callOut = true;
1404 checkZero = true;
1405 callTgt = __aeabi_idiv;
1406 retReg = r0;
1407 break;
1408 /* NOTE: returns in r1 */
1409 case OP_REM_INT:
1410 case OP_REM_INT_2ADDR:
1411 callOut = true;
1412 checkZero = true;
1413 callTgt = __aeabi_idivmod;
1414 retReg = r1;
1415 break;
1416 case OP_AND_INT:
1417 case OP_AND_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001418 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001419 break;
1420 case OP_OR_INT:
1421 case OP_OR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001422 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001423 break;
1424 case OP_XOR_INT:
1425 case OP_XOR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001426 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001427 break;
1428 case OP_SHL_INT:
1429 case OP_SHL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001430 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001431 break;
1432 case OP_SHR_INT:
1433 case OP_SHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001434 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001435 break;
1436 case OP_USHR_INT:
1437 case OP_USHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001438 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001439 break;
1440 default:
1441 LOGE("Invalid word arith op: 0x%x(%d)",
1442 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1443 dvmAbort();
1444 }
1445 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001446 /* Try to allocate reg0 to the currently cached source operand */
1447 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1448 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1449 reg1 = NEXT_REG(reg0);
1450 regDest = NEXT_REG(reg1);
1451
1452 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1453 loadValue(cUnit, vSrc2, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001454 if (threeOperand) {
1455 opRegRegReg(cUnit, op, regDest, reg0, reg1);
1456 storeValue(cUnit, regDest, vDest, reg1);
1457 } else {
1458 opRegReg(cUnit, op, reg0, reg1);
1459 storeValue(cUnit, reg0, vDest, reg1);
1460 }
Ben Chenge9695e52009-06-16 16:11:47 -07001461 } else {
1462 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1463 reg1 = NEXT_REG(reg0);
1464 regDest = NEXT_REG(reg1);
1465
1466 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1467 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001468 if (threeOperand) {
1469 opRegRegReg(cUnit, op, regDest, reg1, reg0);
1470 storeValue(cUnit, regDest, vDest, reg1);
1471 } else {
1472 opRegReg(cUnit, op, reg1, reg0);
1473 storeValue(cUnit, reg1, vDest, reg0);
1474 }
Ben Chenge9695e52009-06-16 16:11:47 -07001475 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001476 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001477 /*
1478 * Load the callout target first since it will never be eliminated
1479 * and its value will be used first.
1480 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001481 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -07001482 /*
1483 * Load vSrc2 first if it is not cached in a native register or it
1484 * is in r0 which will be clobbered if vSrc1 is loaded first.
1485 */
1486 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1487 cUnit->registerScoreboard.nativeReg == r0) {
1488 /* Cannot be optimized and won't clobber r0 */
1489 loadValue(cUnit, vSrc2, r1);
1490 /* May be optimized if vSrc1 is cached */
1491 loadValue(cUnit, vSrc1, r0);
1492 } else {
1493 loadValue(cUnit, vSrc1, r0);
1494 loadValue(cUnit, vSrc2, r1);
1495 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001496 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -07001497 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001498 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001499 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001500 storeValue(cUnit, retReg, vDest, r2);
1501 }
1502 return false;
1503}
1504
1505static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1506{
1507 OpCode opCode = mir->dalvikInsn.opCode;
1508 int vA = mir->dalvikInsn.vA;
1509 int vB = mir->dalvikInsn.vB;
1510 int vC = mir->dalvikInsn.vC;
1511
1512 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1513 return genArithOpLong(cUnit,mir, vA, vA, vB);
1514 }
1515 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1516 return genArithOpLong(cUnit,mir, vA, vB, vC);
1517 }
1518 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1519 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1520 }
1521 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1522 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1523 }
1524 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1525 return genArithOpInt(cUnit,mir, vA, vA, vB);
1526 }
1527 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1528 return genArithOpInt(cUnit,mir, vA, vB, vC);
1529 }
1530 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001531 return genArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001532 }
1533 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001534 return genArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001535 }
1536 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001537 return genArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001538 }
1539 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001540 return genArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001541 }
1542 return true;
1543}
1544
Bill Buzbeed45ba372009-06-15 17:00:57 -07001545static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1546 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001547{
Ben Chenge9695e52009-06-16 16:11:47 -07001548 /*
1549 * Don't optimize the register usage since it calls out to template
1550 * functions
1551 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001552 loadConstant(cUnit, r2, (int)funct);
1553 if (srcSize == 1) {
1554 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1555 } else {
1556 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1557 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001558 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001559 if (tgtSize == 1) {
1560 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1561 } else {
1562 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1563 }
1564 return false;
1565}
1566
Ben Chengba4fc8b2009-06-01 13:00:29 -07001567static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1568 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001569 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001570{
1571 unsigned int i;
1572 unsigned int regMask = 0;
1573
1574 /* Load arguments to r0..r4 */
1575 for (i = 0; i < dInsn->vA; i++) {
1576 regMask |= 1 << i;
1577 loadValue(cUnit, dInsn->arg[i], i);
1578 }
1579 if (regMask) {
1580 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001581 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1582 sizeof(StackSaveArea) + (dInsn->vA << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001583 /* generate null check */
1584 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001585 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1586 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001587 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001588 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001589 }
1590}
1591
1592static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1593 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001594 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001595{
1596 int srcOffset = dInsn->vC << 2;
1597 int numArgs = dInsn->vA;
1598 int regMask;
1599 /*
1600 * r4PC : &rFP[vC]
1601 * r7: &newFP[0]
1602 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001603 opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001604 /* load [r0 .. min(numArgs,4)] */
1605 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001606 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001607
Bill Buzbee270c1d62009-08-13 16:58:07 -07001608 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1609 sizeof(StackSaveArea) + (numArgs << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001610 /* generate null check */
1611 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001612 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001613 }
1614
1615 /*
1616 * Handle remaining 4n arguments:
1617 * store previously loaded 4 values and load the next 4 values
1618 */
1619 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001620 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001621 /*
1622 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001623 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001624 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001625 opImm(cUnit, OP_PUSH, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001626 /* No need to generate the loop structure if numArgs <= 11 */
1627 if (numArgs > 11) {
1628 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001629 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001630 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001631 storeMultiple(cUnit, r7, regMask);
1632 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001633 /* No need to generate the loop structure if numArgs <= 11 */
1634 if (numArgs > 11) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001635 opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001636 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1637 }
1638 }
1639
1640 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001641 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001642
1643 /* Generate the loop epilogue - don't use r0 */
1644 if ((numArgs > 4) && (numArgs % 4)) {
1645 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001646 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001647 }
1648 if (numArgs >= 8)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001649 opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001650
1651 /* Save the modulo 4 arguments */
1652 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001653 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001654 }
1655}
1656
Ben Cheng38329f52009-07-07 14:19:20 -07001657/*
1658 * Generate code to setup the call stack then jump to the chaining cell if it
1659 * is not a native method.
1660 */
1661static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001662 BasicBlock *bb, ArmLIR *labelList,
1663 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001664 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001665{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001666 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001667
1668 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001669 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001670 /* r4PC = dalvikCallsite */
1671 loadConstant(cUnit, r4PC,
1672 (int) (cUnit->method->insns + mir->offset));
1673 addrRetChain->generic.target = (LIR *) retChainingCell;
1674 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001675 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001676 * r1 = &ChainingCell
1677 * r4PC = callsiteDPC
1678 */
1679 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001680 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001681#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001682 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001683#endif
1684 } else {
1685 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1686#if defined(INVOKE_STATS)
1687 gDvmJit.invokeChain++;
1688#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001689 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001690 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1691 }
1692 /* Handle exceptions using the interpreter */
1693 genTrap(cUnit, mir->offset, pcrLabel);
1694}
1695
Ben Cheng38329f52009-07-07 14:19:20 -07001696/*
1697 * Generate code to check the validity of a predicted chain and take actions
1698 * based on the result.
1699 *
1700 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1701 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1702 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1703 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1704 * 0x426a99b2 : blx_2 see above --+
1705 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1706 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1707 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1708 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1709 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1710 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1711 * 0x426a99c0 : blx r7 --+
1712 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1713 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1714 * 0x426a99c6 : blx_2 see above --+
1715 */
1716static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1717 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001718 ArmLIR *retChainingCell,
1719 ArmLIR *predChainingCell,
1720 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001721{
1722 /* "this" is already left in r0 by genProcessArgs* */
1723
1724 /* r4PC = dalvikCallsite */
1725 loadConstant(cUnit, r4PC,
1726 (int) (cUnit->method->insns + mir->offset));
1727
1728 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001729 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001730 addrRetChain->generic.target = (LIR *) retChainingCell;
1731
1732 /* r2 = &predictedChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001733 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, OP_ADD, r2, rpc, 0,
1734 rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001735 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1736
1737 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1738
1739 /* return through lr - jump to the chaining cell */
1740 genUnconditionalBranch(cUnit, predChainingCell);
1741
1742 /*
1743 * null-check on "this" may have been eliminated, but we still need a PC-
1744 * reconstruction label for stack overflow bailout.
1745 */
1746 if (pcrLabel == NULL) {
1747 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001748 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1749 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001750 pcrLabel->operands[0] = dPC;
1751 pcrLabel->operands[1] = mir->offset;
1752 /* Insert the place holder to the growable list */
1753 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1754 }
1755
1756 /* return through lr+2 - punt to the interpreter */
1757 genUnconditionalBranch(cUnit, pcrLabel);
1758
1759 /*
1760 * return through lr+4 - fully resolve the callee method.
1761 * r1 <- count
1762 * r2 <- &predictedChainCell
1763 * r3 <- this->class
1764 * r4 <- dPC
1765 * r7 <- this->class->vtable
1766 */
1767
1768 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001769 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001770
1771 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001772 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001773
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001774 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001775 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001776
Bill Buzbee270c1d62009-08-13 16:58:07 -07001777 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1778 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001779
1780 /*
1781 * r0 = calleeMethod
1782 * r2 = &predictedChainingCell
1783 * r3 = class
1784 *
1785 * &returnChainingCell has been loaded into r1 but is not needed
1786 * when patching the chaining cell and will be clobbered upon
1787 * returning so it will be reconstructed again.
1788 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001789 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001790
1791 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001792 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001793 addrRetChain->generic.target = (LIR *) retChainingCell;
1794
1795 bypassRechaining->generic.target = (LIR *) addrRetChain;
1796 /*
1797 * r0 = calleeMethod,
1798 * r1 = &ChainingCell,
1799 * r4PC = callsiteDPC,
1800 */
1801 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1802#if defined(INVOKE_STATS)
1803 gDvmJit.invokePredictedChain++;
1804#endif
1805 /* Handle exceptions using the interpreter */
1806 genTrap(cUnit, mir->offset, pcrLabel);
1807}
1808
1809/*
1810 * Up calling this function, "this" is stored in r0. The actual class will be
1811 * chased down off r0 and the predicted one will be retrieved through
1812 * predictedChainingCell then a comparison is performed to see whether the
1813 * previously established chaining is still valid.
1814 *
1815 * The return LIR is a branch based on the comparison result. The actual branch
1816 * target will be setup in the caller.
1817 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001818static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1819 ArmLIR *predChainingCell,
1820 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001821 MIR *mir)
1822{
1823 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001824 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001825
1826 /*
1827 * r2 now contains predicted class. The starting offset of the
1828 * cached value is 4 bytes into the chaining cell.
1829 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001830 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001831 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07001832 getPredictedClass->generic.target = (LIR *) predChainingCell;
1833
1834 /*
1835 * r0 now contains predicted method. The starting offset of the
1836 * cached value is 8 bytes into the chaining cell.
1837 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001838 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001839 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001840 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1841
1842 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001843 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001844 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001845 getRechainingRequestCount->generic.target =
1846 (LIR *) predChainingCell;
1847
1848 /* r4PC = dalvikCallsite */
1849 loadConstant(cUnit, r4PC,
1850 (int) (cUnit->method->insns + mir->offset));
1851
1852 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001853 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001854 addrRetChain->generic.target = (LIR *) retChainingCell;
1855
1856 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001857 opRegReg(cUnit, OP_CMP, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001858
Bill Buzbee270c1d62009-08-13 16:58:07 -07001859 return opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001860}
1861
Ben Chengba4fc8b2009-06-01 13:00:29 -07001862/* Geneate a branch to go back to the interpreter */
1863static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1864{
1865 /* r0 = dalvik pc */
1866 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001867 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1868 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1869 jitToInterpEntries.dvmJitToInterpPunt), r1);
1870 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001871}
1872
1873/*
1874 * Attempt to single step one instruction using the interpreter and return
1875 * to the compiled code for the next Dalvik instruction
1876 */
1877static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1878{
1879 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1880 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1881 kInstrCanThrow;
1882 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1883 genPuntToInterp(cUnit, mir->offset);
1884 return;
1885 }
1886 int entryAddr = offsetof(InterpState,
1887 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001888 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001889 /* r0 = dalvik pc */
1890 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1891 /* r1 = dalvik pc of following instruction */
1892 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001893 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001894}
1895
Bill Buzbee270c1d62009-08-13 16:58:07 -07001896/* Generate conditional branch instructions */
1897static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1898 ArmConditionCode cond,
1899 ArmLIR *target)
1900{
1901 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
1902 branch->generic.target = (LIR *) target;
1903 return branch;
1904}
Ben Chengba4fc8b2009-06-01 13:00:29 -07001905
Bill Buzbee270c1d62009-08-13 16:58:07 -07001906/* Generate unconditional branch instructions */
1907static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1908{
1909 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
1910 branch->generic.target = (LIR *) target;
1911 return branch;
1912}
1913
1914/* Load the address of a Dalvik register on the frame */
1915static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
1916{
1917 return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
1918}
1919
1920/* Load a single value from rFP[src] and store them into rDest */
1921static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
1922{
1923 return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
1924}
1925
1926/* Load a word at base + displacement. Displacement must be word multiple */
1927static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
1928 int rDest)
1929{
1930 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
1931 -1);
1932}
1933
1934static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
1935 int displacement, int rSrc, int rScratch)
1936{
1937 return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
1938}
1939
1940/* Store a value from rSrc to vDest */
1941static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
1942 int rScratch)
1943{
1944 killNullCheckedRegister(cUnit, vDest);
1945 updateLiveRegister(cUnit, vDest, rSrc);
1946 return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
1947}
1948/*
1949 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
1950 * rDestHi
1951 */
1952static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
1953 int rDestHi)
1954{
1955 ArmLIR *res;
1956 /* Use reg + imm5*4 to load the values if possible */
1957 if (vSrc <= 30) {
1958 res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
1959 loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
1960 } else {
1961 assert(rDestLo < rDestHi);
1962 res = loadValueAddress(cUnit, vSrc, rDestLo);
1963 loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
1964 }
1965 return res;
1966}
1967
1968/*
1969 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
1970 * vDest+1
1971 */
1972static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
1973 int vDest, int rScratch)
1974{
1975 ArmLIR *res;
1976 killNullCheckedRegister(cUnit, vDest);
1977 killNullCheckedRegister(cUnit, vDest+1);
1978 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
1979
1980 /* Use reg + imm5*4 to store the values if possible */
1981 if (vDest <= 30) {
1982 res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
1983 storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
1984 } else {
1985 assert(rSrcLo < rSrcHi);
1986 res = loadValueAddress(cUnit, vDest, rScratch);
1987 storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
1988 }
1989 return res;
1990}
1991
1992static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1993{
1994 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
1995 dvmCompilerAppendLIR(cUnit, (LIR*)res);
1996 return res;
1997}
1998
Ben Chengba4fc8b2009-06-01 13:00:29 -07001999/*
2000 * The following are the first-level codegen routines that analyze the format
2001 * of each bytecode then either dispatch special purpose codegen routines
2002 * or produce corresponding Thumb instructions directly.
2003 */
2004
2005static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002006 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002007{
2008 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2009 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2010 return false;
2011}
2012
2013static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
2014{
2015 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2016 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
2017 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
2018 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2019 return true;
2020 }
2021 switch (dalvikOpCode) {
2022 case OP_RETURN_VOID:
2023 genReturnCommon(cUnit,mir);
2024 break;
2025 case OP_UNUSED_73:
2026 case OP_UNUSED_79:
2027 case OP_UNUSED_7A:
2028 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2029 return true;
2030 case OP_NOP:
2031 break;
2032 default:
2033 return true;
2034 }
2035 return false;
2036}
2037
2038static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2039{
Ben Chenge9695e52009-06-16 16:11:47 -07002040 int reg0, reg1, reg2;
2041
Ben Chengba4fc8b2009-06-01 13:00:29 -07002042 switch (mir->dalvikInsn.opCode) {
2043 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07002044 case OP_CONST_4: {
2045 /* Avoid using the previously used register */
2046 reg0 = selectFirstRegister(cUnit, vNone, false);
2047 reg1 = NEXT_REG(reg0);
2048 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
2049 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002050 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002051 }
2052 case OP_CONST_WIDE_32: {
2053 /* Avoid using the previously used register */
2054 reg0 = selectFirstRegister(cUnit, vNone, true);
2055 reg1 = NEXT_REG(reg0);
2056 reg2 = NEXT_REG(reg1);
2057 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002058 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002059 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002060 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002061 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002062 default:
2063 return true;
2064 }
2065 return false;
2066}
2067
2068static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2069{
Ben Chenge9695e52009-06-16 16:11:47 -07002070 int reg0, reg1, reg2;
2071
2072 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002073 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07002074 case OP_CONST_HIGH16: {
2075 reg0 = selectFirstRegister(cUnit, vNone, false);
2076 reg1 = NEXT_REG(reg0);
2077 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
2078 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002079 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002080 }
2081 case OP_CONST_WIDE_HIGH16: {
2082 reg0 = selectFirstRegister(cUnit, vNone, true);
2083 reg1 = NEXT_REG(reg0);
2084 reg2 = NEXT_REG(reg1);
2085 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
2086 loadConstant(cUnit, reg0, 0);
2087 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002088 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002089 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002090 default:
2091 return true;
2092 }
2093 return false;
2094}
2095
2096static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2097{
2098 /* For OP_THROW_VERIFICATION_ERROR */
2099 genInterpSingleStep(cUnit, mir);
2100 return false;
2101}
2102
2103static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2104{
Ben Chenge9695e52009-06-16 16:11:47 -07002105 /* Native register to use if the interested value is vA */
2106 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2107 /* Native register to use if source is not from Dalvik registers */
2108 int regvNone = selectFirstRegister(cUnit, vNone, false);
2109 /* Similar to regvA but for 64-bit values */
2110 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
2111 /* Similar to regvNone but for 64-bit values */
2112 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
2113
Ben Chengba4fc8b2009-06-01 13:00:29 -07002114 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002115 case OP_CONST_STRING_JUMBO:
2116 case OP_CONST_STRING: {
2117 void *strPtr = (void*)
2118 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2119 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002120 loadConstant(cUnit, regvNone, (int) strPtr );
2121 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002122 break;
2123 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002124 case OP_CONST_CLASS: {
2125 void *classPtr = (void*)
2126 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2127 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002128 loadConstant(cUnit, regvNone, (int) classPtr );
2129 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002130 break;
2131 }
2132 case OP_SGET_OBJECT:
2133 case OP_SGET_BOOLEAN:
2134 case OP_SGET_CHAR:
2135 case OP_SGET_BYTE:
2136 case OP_SGET_SHORT:
2137 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002138 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002139 void *fieldPtr = (void*)
2140 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2141 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002142 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002143#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002144 loadWordDisp(cUnit, regvNone, 0, regvNone);
Jeff Hao97319a82009-08-12 16:57:15 -07002145#else
2146 int regMap = regvNone << 4 | regvNone;
2147 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2148
Jeff Hao97319a82009-08-12 16:57:15 -07002149#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002150 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002151 break;
2152 }
2153 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002154 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002155 void *fieldPtr = (void*)
2156 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002157 int reg0, reg1, reg2;
2158
Ben Chengba4fc8b2009-06-01 13:00:29 -07002159 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002160 reg0 = regvNoneWide;
2161 reg1 = NEXT_REG(reg0);
2162 reg2 = NEXT_REG(reg1);
2163 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002164#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002165 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002166#else
2167 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2168 selfVerificationMemOpWrapper(cUnit, regMap,
2169 &selfVerificationLoadDoubleword);
2170
Jeff Hao97319a82009-08-12 16:57:15 -07002171#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002172 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002173 break;
2174 }
2175 case OP_SPUT_OBJECT:
2176 case OP_SPUT_BOOLEAN:
2177 case OP_SPUT_CHAR:
2178 case OP_SPUT_BYTE:
2179 case OP_SPUT_SHORT:
2180 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002181 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002182 void *fieldPtr = (void*)
2183 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002184
Ben Chengba4fc8b2009-06-01 13:00:29 -07002185 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002186 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
2187 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
2188 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002189#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002190 storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
Jeff Hao97319a82009-08-12 16:57:15 -07002191#else
2192 int regMap = regvA << 4 | NEXT_REG(regvA);
2193 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2194#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002195 break;
2196 }
2197 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002198 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002199 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002200 void *fieldPtr = (void*)
2201 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002202
Ben Chengba4fc8b2009-06-01 13:00:29 -07002203 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002204 reg0 = regvAWide;
2205 reg1 = NEXT_REG(reg0);
2206 reg2 = NEXT_REG(reg1);
2207 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2208 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2209 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002210#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002211 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002212#else
2213 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2214 selfVerificationMemOpWrapper(cUnit, regMap,
2215 &selfVerificationStoreDoubleword);
2216#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002217 break;
2218 }
2219 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002220 /*
2221 * Obey the calling convention and don't mess with the register
2222 * usage.
2223 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002224 ClassObject *classPtr = (void*)
2225 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2226 assert(classPtr != NULL);
2227 assert(classPtr->status & CLASS_INITIALIZED);
2228 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
2229 /* It's going to throw, just let the interp. deal with it. */
2230 genInterpSingleStep(cUnit, mir);
2231 return false;
2232 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002233 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002234 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002235 genExportPC(cUnit, mir, r2, r3 );
2236 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002237 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002238 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002239 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2240 break;
2241 }
2242 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002243 /*
2244 * Obey the calling convention and don't mess with the register
2245 * usage.
2246 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002247 ClassObject *classPtr =
2248 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2249 loadConstant(cUnit, r1, (int) classPtr );
2250 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002251 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* Null? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002252 ArmLIR *branch1 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002253 opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002254 /* r0 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002255 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002256 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002257 opRegReg(cUnit, OP_CMP, r0, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002258 ArmLIR *branch2 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002259 opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2260 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002261 /* check cast failed - punt to the interpreter */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002262 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002263 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002264 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002265 branch1->generic.target = (LIR *)target;
2266 branch2->generic.target = (LIR *)target;
2267 break;
2268 }
2269 default:
2270 return true;
2271 }
2272 return false;
2273}
2274
2275static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2276{
2277 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2278 switch (dalvikOpCode) {
2279 case OP_MOVE_EXCEPTION: {
2280 int offset = offsetof(InterpState, self);
2281 int exOffset = offsetof(Thread, exception);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002282 loadWordDisp(cUnit, rGLUE, offset, r1);
2283 loadWordDisp(cUnit, r1, exOffset, r0);
Ben Chenge9695e52009-06-16 16:11:47 -07002284 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002285 break;
2286 }
2287 case OP_MOVE_RESULT:
2288 case OP_MOVE_RESULT_OBJECT: {
2289 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002290 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002291 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2292 break;
2293 }
2294 case OP_MOVE_RESULT_WIDE: {
2295 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002296 loadWordDisp(cUnit, rGLUE, offset, r0);
2297 loadWordDisp(cUnit, rGLUE, offset+4, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002298 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2299 break;
2300 }
2301 case OP_RETURN_WIDE: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002302 int vSrc = mir->dalvikInsn.vA;
2303 int reg0 = selectFirstRegister(cUnit, vSrc, true);
2304 int reg1 = NEXT_REG(reg0);
2305 int rScratch = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002306 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002307 loadValuePair(cUnit, vSrc, reg0, reg1);
2308 storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
2309 storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002310 genReturnCommon(cUnit,mir);
2311 break;
2312 }
2313 case OP_RETURN:
2314 case OP_RETURN_OBJECT: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002315 int vSrc = mir->dalvikInsn.vA;
2316 int reg0 = selectFirstRegister(cUnit, vSrc, false);
2317 int rScratch = NEXT_REG(reg0);
2318 loadValue(cUnit, vSrc, reg0);
2319 storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
2320 reg0, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002321 genReturnCommon(cUnit,mir);
2322 break;
2323 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002324 case OP_MONITOR_ENTER:
2325 case OP_MONITOR_EXIT: {
2326 int offset = offsetof(InterpState, self);
2327 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002328 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002329 if (dalvikOpCode == OP_MONITOR_ENTER) {
2330 loadConstant(cUnit, r2, (int)dvmLockObject);
2331 } else {
2332 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2333 }
Ben Chenge9695e52009-06-16 16:11:47 -07002334 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002335 /* Do the call */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002336 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002337 break;
2338 }
2339 case OP_THROW: {
2340 genInterpSingleStep(cUnit, mir);
2341 break;
2342 }
2343 default:
2344 return true;
2345 }
2346 return false;
2347}
2348
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002349static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002350{
2351 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002352
Ben Chengba4fc8b2009-06-01 13:00:29 -07002353 float __aeabi_i2f( int op1 );
2354 int __aeabi_f2iz( float op1 );
2355 float __aeabi_d2f( double op1 );
2356 double __aeabi_f2d( float op1 );
2357 double __aeabi_i2d( int op1 );
2358 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002359 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002360 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002361 s8 dvmJitf2l( float op1 );
2362 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002363
Bill Buzbeed45ba372009-06-15 17:00:57 -07002364 switch (opCode) {
2365 case OP_INT_TO_FLOAT:
2366 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2367 case OP_FLOAT_TO_INT:
2368 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2369 case OP_DOUBLE_TO_FLOAT:
2370 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2371 case OP_FLOAT_TO_DOUBLE:
2372 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2373 case OP_INT_TO_DOUBLE:
2374 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2375 case OP_DOUBLE_TO_INT:
2376 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2377 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002378 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002379 case OP_LONG_TO_FLOAT:
2380 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2381 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002382 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002383 case OP_LONG_TO_DOUBLE:
2384 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2385 default:
2386 return true;
2387 }
2388 return false;
2389}
2390
2391static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2392{
2393 OpCode opCode = mir->dalvikInsn.opCode;
2394 int vSrc1Dest = mir->dalvikInsn.vA;
2395 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002396 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002397
Ben Chengba4fc8b2009-06-01 13:00:29 -07002398 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2399 return genArithOp( cUnit, mir );
2400 }
2401
Ben Chenge9695e52009-06-16 16:11:47 -07002402 /*
2403 * If data type is 64-bit, re-calculate the register numbers in the
2404 * corresponding cases.
2405 */
2406 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2407 reg1 = NEXT_REG(reg0);
2408 reg2 = NEXT_REG(reg1);
2409
Ben Chengba4fc8b2009-06-01 13:00:29 -07002410 switch (opCode) {
2411 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002412 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002413 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002414 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002415 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002416 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002417 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002418 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002419 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002420 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002421 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002422 case OP_NEG_INT:
2423 case OP_NOT_INT:
2424 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2425 case OP_NEG_LONG:
2426 case OP_NOT_LONG:
2427 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2428 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002429 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002430 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002431 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07002432 case OP_MOVE_WIDE: {
2433 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2434 reg1 = NEXT_REG(reg0);
2435 reg2 = NEXT_REG(reg1);
2436
2437 loadValuePair(cUnit, vSrc2, reg0, reg1);
2438 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002439 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002440 }
2441 case OP_INT_TO_LONG: {
2442 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2443 reg1 = NEXT_REG(reg0);
2444 reg2 = NEXT_REG(reg1);
2445
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002446 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002447 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002448 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002449 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002450 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002451 case OP_MOVE:
2452 case OP_MOVE_OBJECT:
2453 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002454 loadValue(cUnit, vSrc2, reg0);
2455 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002456 break;
2457 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07002458 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002459 opRegReg(cUnit, OP_2BYTE, reg1, reg0);
2460 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002461 break;
2462 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07002463 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002464 opRegReg(cUnit, OP_2SHORT, reg1, reg0);
2465 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002466 break;
2467 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07002468 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002469 opRegReg(cUnit, OP_2CHAR, reg1, reg0);
2470 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002471 break;
2472 case OP_ARRAY_LENGTH: {
2473 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002474 loadValue(cUnit, vSrc2, reg1);
2475 genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
2476 loadWordDisp(cUnit, reg1, lenOffset, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -07002477 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002478 break;
2479 }
2480 default:
2481 return true;
2482 }
2483 return false;
2484}
2485
2486static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2487{
2488 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07002489 int reg0, reg1, reg2;
2490
Ben Chengba4fc8b2009-06-01 13:00:29 -07002491 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2492 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002493 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002494 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002495
2496 reg0 = selectFirstRegister(cUnit, vNone, true);
2497 reg1 = NEXT_REG(reg0);
2498 reg2 = NEXT_REG(reg1);
2499
2500 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002501 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002502
2503 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07002504 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002505 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002506 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002507 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002508
Ben Chenge9695e52009-06-16 16:11:47 -07002509 reg0 = selectFirstRegister(cUnit, vNone, false);
2510 reg1 = NEXT_REG(reg0);
2511
2512 loadConstant(cUnit, reg0, BBBB);
2513 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002514 } else {
2515 return true;
2516 }
2517 return false;
2518}
2519
2520/* Compare agaist zero */
2521static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002522 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002523{
2524 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002525 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002526 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002527
Ben Chenge9695e52009-06-16 16:11:47 -07002528 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002529 opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002530
Bill Buzbee270c1d62009-08-13 16:58:07 -07002531//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002532 switch (dalvikOpCode) {
2533 case OP_IF_EQZ:
2534 cond = ARM_COND_EQ;
2535 break;
2536 case OP_IF_NEZ:
2537 cond = ARM_COND_NE;
2538 break;
2539 case OP_IF_LTZ:
2540 cond = ARM_COND_LT;
2541 break;
2542 case OP_IF_GEZ:
2543 cond = ARM_COND_GE;
2544 break;
2545 case OP_IF_GTZ:
2546 cond = ARM_COND_GT;
2547 break;
2548 case OP_IF_LEZ:
2549 cond = ARM_COND_LE;
2550 break;
2551 default:
2552 cond = 0;
2553 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2554 dvmAbort();
2555 }
2556 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2557 /* This mostly likely will be optimized away in a later phase */
2558 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2559 return false;
2560}
2561
2562static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2563{
2564 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2565 int vSrc = mir->dalvikInsn.vB;
2566 int vDest = mir->dalvikInsn.vA;
2567 int lit = mir->dalvikInsn.vC;
Bill Buzbee270c1d62009-08-13 16:58:07 -07002568 OpKind op;
Ben Chenge9695e52009-06-16 16:11:47 -07002569 int reg0, reg1, regDest;
2570
2571 reg0 = selectFirstRegister(cUnit, vSrc, false);
2572 reg1 = NEXT_REG(reg0);
2573 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002574
Ben Chengba4fc8b2009-06-01 13:00:29 -07002575 int __aeabi_idivmod(int op1, int op2);
2576 int __aeabi_idiv(int op1, int op2);
2577
2578 switch (dalvikOpCode) {
2579 case OP_ADD_INT_LIT8:
2580 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002581 loadValue(cUnit, vSrc, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002582 opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
2583 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002584 break;
2585
2586 case OP_RSUB_INT_LIT8:
2587 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002588 loadValue(cUnit, vSrc, reg1);
2589 loadConstant(cUnit, reg0, lit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002590 opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
2591 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002592 break;
2593
2594 case OP_MUL_INT_LIT8:
2595 case OP_MUL_INT_LIT16:
2596 case OP_AND_INT_LIT8:
2597 case OP_AND_INT_LIT16:
2598 case OP_OR_INT_LIT8:
2599 case OP_OR_INT_LIT16:
2600 case OP_XOR_INT_LIT8:
2601 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002602 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002603 switch (dalvikOpCode) {
2604 case OP_MUL_INT_LIT8:
2605 case OP_MUL_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002606 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002607 break;
2608 case OP_AND_INT_LIT8:
2609 case OP_AND_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002610 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002611 break;
2612 case OP_OR_INT_LIT8:
2613 case OP_OR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002614 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002615 break;
2616 case OP_XOR_INT_LIT8:
2617 case OP_XOR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002618 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002619 break;
2620 default:
2621 dvmAbort();
2622 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002623 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2624 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002625 break;
2626
2627 case OP_SHL_INT_LIT8:
2628 case OP_SHR_INT_LIT8:
2629 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002630 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002631 switch (dalvikOpCode) {
2632 case OP_SHL_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002633 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002634 break;
2635 case OP_SHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002636 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002637 break;
2638 case OP_USHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002639 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002640 break;
2641 default: dvmAbort();
2642 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002643 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2644 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002645 break;
2646
2647 case OP_DIV_INT_LIT8:
2648 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002649 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002650 if (lit == 0) {
2651 /* Let the interpreter deal with div by 0 */
2652 genInterpSingleStep(cUnit, mir);
2653 return false;
2654 }
2655 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2656 loadConstant(cUnit, r1, lit);
2657 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002658 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002659 storeValue(cUnit, r0, vDest, r2);
2660 break;
2661
2662 case OP_REM_INT_LIT8:
2663 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002664 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002665 if (lit == 0) {
2666 /* Let the interpreter deal with div by 0 */
2667 genInterpSingleStep(cUnit, mir);
2668 return false;
2669 }
2670 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2671 loadConstant(cUnit, r1, lit);
2672 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002673 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002674 storeValue(cUnit, r1, vDest, r2);
2675 break;
2676 default:
2677 return true;
2678 }
2679 return false;
2680}
2681
2682static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2683{
2684 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2685 int fieldOffset;
2686
2687 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2688 InstField *pInstField = (InstField *)
2689 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2690 int fieldOffset;
2691
2692 assert(pInstField != NULL);
2693 fieldOffset = pInstField->byteOffset;
2694 } else {
2695 /* To make the compiler happy */
2696 fieldOffset = 0;
2697 }
2698 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002699 case OP_NEW_ARRAY: {
2700 void *classPtr = (void*)
2701 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2702 assert(classPtr != NULL);
2703 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2704 loadConstant(cUnit, r0, (int) classPtr );
2705 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002706 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002707 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2708 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002709 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2710 opReg(cUnit, OP_BLX, r4PC);
2711 /* Note: on failure, we'll bail and reinterpret */
Ben Chenge9695e52009-06-16 16:11:47 -07002712 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002713 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2714 break;
2715 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002716 case OP_INSTANCE_OF: {
2717 ClassObject *classPtr =
2718 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2719 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002720 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002721 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002722//TUNING: compare to 0 primative to allow use of CB[N]Z
2723 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002724 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002725 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002726 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002727 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002728 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002729 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002730 opRegReg(cUnit, OP_CMP, r1, r2);
2731 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2732 opRegReg(cUnit, OP_MOV, r0, r1);
2733 opRegReg(cUnit, OP_MOV, r1, r2);
2734 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002735 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002736 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002737 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2738 branch1->generic.target = (LIR *)target;
2739 branch2->generic.target = (LIR *)target;
2740 break;
2741 }
2742 case OP_IGET_WIDE:
2743 genIGetWide(cUnit, mir, fieldOffset);
2744 break;
2745 case OP_IGET:
2746 case OP_IGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002747 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002748 break;
2749 case OP_IGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002750 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002751 break;
2752 case OP_IGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002753 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002754 break;
2755 case OP_IGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002756 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002757 break;
2758 case OP_IGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002759 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002760 break;
2761 case OP_IPUT_WIDE:
2762 genIPutWide(cUnit, mir, fieldOffset);
2763 break;
2764 case OP_IPUT:
2765 case OP_IPUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002766 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002767 break;
2768 case OP_IPUT_SHORT:
2769 case OP_IPUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002770 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002771 break;
2772 case OP_IPUT_BYTE:
2773 case OP_IPUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002774 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002775 break;
2776 default:
2777 return true;
2778 }
2779 return false;
2780}
2781
2782static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2783{
2784 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2785 int fieldOffset = mir->dalvikInsn.vC;
2786 switch (dalvikOpCode) {
2787 case OP_IGET_QUICK:
2788 case OP_IGET_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002789 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002790 break;
2791 case OP_IPUT_QUICK:
2792 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002793 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002794 break;
2795 case OP_IGET_WIDE_QUICK:
2796 genIGetWide(cUnit, mir, fieldOffset);
2797 break;
2798 case OP_IPUT_WIDE_QUICK:
2799 genIPutWide(cUnit, mir, fieldOffset);
2800 break;
2801 default:
2802 return true;
2803 }
2804 return false;
2805
2806}
2807
2808/* Compare agaist zero */
2809static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002810 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002811{
2812 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002813 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002814 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002815
Ben Chenge9695e52009-06-16 16:11:47 -07002816 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2817 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2818 reg1 = NEXT_REG(reg0);
2819 /* Load vB first since vA can be fetched via a move */
2820 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2821 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2822 } else {
2823 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2824 reg1 = NEXT_REG(reg0);
2825 /* Load vA first since vB can be fetched via a move */
2826 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2827 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2828 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002829 opRegReg(cUnit, OP_CMP, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002830
2831 switch (dalvikOpCode) {
2832 case OP_IF_EQ:
2833 cond = ARM_COND_EQ;
2834 break;
2835 case OP_IF_NE:
2836 cond = ARM_COND_NE;
2837 break;
2838 case OP_IF_LT:
2839 cond = ARM_COND_LT;
2840 break;
2841 case OP_IF_GE:
2842 cond = ARM_COND_GE;
2843 break;
2844 case OP_IF_GT:
2845 cond = ARM_COND_GT;
2846 break;
2847 case OP_IF_LE:
2848 cond = ARM_COND_LE;
2849 break;
2850 default:
2851 cond = 0;
2852 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2853 dvmAbort();
2854 }
2855 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2856 /* This mostly likely will be optimized away in a later phase */
2857 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2858 return false;
2859}
2860
2861static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2862{
2863 OpCode opCode = mir->dalvikInsn.opCode;
2864 int vSrc1Dest = mir->dalvikInsn.vA;
2865 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002866 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002867
2868 switch (opCode) {
2869 case OP_MOVE_16:
2870 case OP_MOVE_OBJECT_16:
2871 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002872 case OP_MOVE_OBJECT_FROM16: {
2873 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2874 reg1 = NEXT_REG(reg0);
2875 loadValue(cUnit, vSrc2, reg0);
2876 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002877 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002878 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002879 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002880 case OP_MOVE_WIDE_FROM16: {
2881 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2882 reg1 = NEXT_REG(reg0);
2883 reg2 = NEXT_REG(reg1);
2884 loadValuePair(cUnit, vSrc2, reg0, reg1);
2885 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002886 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002887 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002888 default:
2889 return true;
2890 }
2891 return false;
2892}
2893
2894static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2895{
2896 OpCode opCode = mir->dalvikInsn.opCode;
2897 int vA = mir->dalvikInsn.vA;
2898 int vB = mir->dalvikInsn.vB;
2899 int vC = mir->dalvikInsn.vC;
2900
Ben Chenge9695e52009-06-16 16:11:47 -07002901 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002902 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2903 return genArithOp( cUnit, mir );
2904 }
2905
2906 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002907 case OP_CMPL_FLOAT:
2908 case OP_CMPG_FLOAT:
2909 case OP_CMPL_DOUBLE:
2910 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002911 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002912 case OP_CMP_LONG:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07002913 genCmpLong(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002914 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002915 case OP_AGET_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002916 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002917 break;
2918 case OP_AGET:
2919 case OP_AGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002920 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002921 break;
2922 case OP_AGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002923 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002924 break;
2925 case OP_AGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002926 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002927 break;
2928 case OP_AGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002929 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002930 break;
2931 case OP_AGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002932 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002933 break;
2934 case OP_APUT_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002935 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002936 break;
2937 case OP_APUT:
2938 case OP_APUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002939 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002940 break;
2941 case OP_APUT_SHORT:
2942 case OP_APUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002943 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002944 break;
2945 case OP_APUT_BYTE:
2946 case OP_APUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002947 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002948 break;
2949 default:
2950 return true;
2951 }
2952 return false;
2953}
2954
2955static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2956{
2957 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2958 switch (dalvikOpCode) {
2959 case OP_FILL_ARRAY_DATA: {
2960 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2961 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2962 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2963 (int) (cUnit->method->insns + mir->offset));
2964 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002965 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002966 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002967 break;
2968 }
2969 /*
2970 * TODO
2971 * - Add a 1 to 3-entry per-location cache here to completely
2972 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2973 * - Use out-of-line handlers for both of these
2974 */
2975 case OP_PACKED_SWITCH:
2976 case OP_SPARSE_SWITCH: {
2977 if (dalvikOpCode == OP_PACKED_SWITCH) {
2978 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2979 } else {
2980 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2981 }
2982 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2983 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2984 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002985 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002986 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002987 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2988 jitToInterpEntries.dvmJitToInterpNoChain), r2);
2989 opRegReg(cUnit, OP_ADD, r0, r0);
2990 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
2991 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002992 break;
2993 }
2994 default:
2995 return true;
2996 }
2997 return false;
2998}
2999
3000static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003001 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003002{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003003 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003004 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003005
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003006 if (bb->fallThrough != NULL)
3007 retChainingCell = &labelList[bb->fallThrough->id];
3008
Ben Chengba4fc8b2009-06-01 13:00:29 -07003009 DecodedInstruction *dInsn = &mir->dalvikInsn;
3010 switch (mir->dalvikInsn.opCode) {
3011 /*
3012 * calleeMethod = this->clazz->vtable[
3013 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3014 * ]
3015 */
3016 case OP_INVOKE_VIRTUAL:
3017 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003018 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003019 int methodIndex =
3020 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3021 methodIndex;
3022
3023 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3024 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3025 else
3026 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3027
Ben Cheng38329f52009-07-07 14:19:20 -07003028 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3029 retChainingCell,
3030 predChainingCell,
3031 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003032 break;
3033 }
3034 /*
3035 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3036 * ->pResMethods[BBBB]->methodIndex]
3037 */
3038 /* TODO - not excersized in RunPerf.jar */
3039 case OP_INVOKE_SUPER:
3040 case OP_INVOKE_SUPER_RANGE: {
3041 int mIndex = cUnit->method->clazz->pDvmDex->
3042 pResMethods[dInsn->vB]->methodIndex;
3043 const Method *calleeMethod =
3044 cUnit->method->clazz->super->vtable[mIndex];
3045
3046 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3047 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3048 else
3049 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3050
3051 /* r0 = calleeMethod */
3052 loadConstant(cUnit, r0, (int) calleeMethod);
3053
Ben Cheng38329f52009-07-07 14:19:20 -07003054 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3055 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003056 break;
3057 }
3058 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3059 case OP_INVOKE_DIRECT:
3060 case OP_INVOKE_DIRECT_RANGE: {
3061 const Method *calleeMethod =
3062 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3063
3064 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3065 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3066 else
3067 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3068
3069 /* r0 = calleeMethod */
3070 loadConstant(cUnit, r0, (int) calleeMethod);
3071
Ben Cheng38329f52009-07-07 14:19:20 -07003072 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3073 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003074 break;
3075 }
3076 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3077 case OP_INVOKE_STATIC:
3078 case OP_INVOKE_STATIC_RANGE: {
3079 const Method *calleeMethod =
3080 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3081
3082 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3083 genProcessArgsNoRange(cUnit, mir, dInsn,
3084 NULL /* no null check */);
3085 else
3086 genProcessArgsRange(cUnit, mir, dInsn,
3087 NULL /* no null check */);
3088
3089 /* r0 = calleeMethod */
3090 loadConstant(cUnit, r0, (int) calleeMethod);
3091
Ben Cheng38329f52009-07-07 14:19:20 -07003092 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3093 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003094 break;
3095 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07003096/*
3097 * TODO: When we move to using upper registers in Thumb2, make sure
3098 * the register allocater is told that r9, r10, & r12 are killed
3099 * here.
3100 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003101 /*
3102 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3103 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003104 *
3105 * Given "invoke-interface {v0}", the following is the generated code:
3106 *
3107 * 0x426a9abe : ldr r0, [r5, #0] --+
3108 * 0x426a9ac0 : mov r7, r5 |
3109 * 0x426a9ac2 : sub r7, #24 |
3110 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3111 * 0x426a9ac6 : beq 0x426a9afe |
3112 * 0x426a9ac8 : stmia r7, <r0> --+
3113 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3114 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3115 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3116 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3117 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3118 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3119 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
3120 * 0x426a9ad8 : mov r9, r1 --+
3121 * 0x426a9ada : mov r10, r2 |
3122 * 0x426a9adc : mov r12, r3 |
3123 * 0x426a9ade : mov r0, r3 |
3124 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3125 * 0x426a9ae2 : ldr r2, [pc, #76] |
3126 * 0x426a9ae4 : ldr r3, [pc, #68] |
3127 * 0x426a9ae6 : ldr r7, [pc, #64] |
3128 * 0x426a9ae8 : blx r7 --+
3129 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
3130 * 0x426a9aec : cmp r1, #0 --> compare against 0
3131 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3132 * 0x426a9af0 : ldr r7, [r6, #96] --+
3133 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3134 * 0x426a9af4 : mov r3, r12 |
3135 * 0x426a9af6 : blx r7 --+
3136 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3137 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3138 * 0x426a9afc : blx_2 see above --+
3139 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3140 * 0x426a9afe (0042): ldr r0, [pc, #52]
3141 * Exception_Handling:
3142 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3143 * 0x426a9b02 (0046): blx r1
3144 * 0x426a9b04 (0048): .align4
3145 * -------- chaining cell (hot): 0x0021
3146 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3147 * 0x426a9b06 (004a): blx r0
3148 * 0x426a9b08 (004c): data 0x7872(30834)
3149 * 0x426a9b0a (004e): data 0x428b(17035)
3150 * 0x426a9b0c (0050): .align4
3151 * -------- chaining cell (predicted)
3152 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3153 * 0x426a9b0e (0052): data 0x0000(0)
3154 * 0x426a9b10 (0054): data 0x0000(0) --> class
3155 * 0x426a9b12 (0056): data 0x0000(0)
3156 * 0x426a9b14 (0058): data 0x0000(0) --> method
3157 * 0x426a9b16 (005a): data 0x0000(0)
3158 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3159 * 0x426a9b1a (005e): data 0x0000(0)
3160 * 0x426a9b28 (006c): .word (0xad0392a5)
3161 * 0x426a9b2c (0070): .word (0x6e750)
3162 * 0x426a9b30 (0074): .word (0x4109a618)
3163 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003164 */
3165 case OP_INVOKE_INTERFACE:
3166 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003167 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003168 int methodIndex = dInsn->vB;
3169
3170 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3171 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3172 else
3173 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3174
Ben Cheng38329f52009-07-07 14:19:20 -07003175 /* "this" is already left in r0 by genProcessArgs* */
3176
3177 /* r4PC = dalvikCallsite */
3178 loadConstant(cUnit, r4PC,
3179 (int) (cUnit->method->insns + mir->offset));
3180
3181 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003182 ArmLIR *addrRetChain =
3183 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003184 addrRetChain->generic.target = (LIR *) retChainingCell;
3185
3186 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003187 ArmLIR *predictedChainingCell =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003188 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003189 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3190
3191 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3192
3193 /* return through lr - jump to the chaining cell */
3194 genUnconditionalBranch(cUnit, predChainingCell);
3195
3196 /*
3197 * null-check on "this" may have been eliminated, but we still need
3198 * a PC-reconstruction label for stack overflow bailout.
3199 */
3200 if (pcrLabel == NULL) {
3201 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003202 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3203 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003204 pcrLabel->operands[0] = dPC;
3205 pcrLabel->operands[1] = mir->offset;
3206 /* Insert the place holder to the growable list */
3207 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3208 }
3209
3210 /* return through lr+2 - punt to the interpreter */
3211 genUnconditionalBranch(cUnit, pcrLabel);
3212
3213 /*
3214 * return through lr+4 - fully resolve the callee method.
3215 * r1 <- count
3216 * r2 <- &predictedChainCell
3217 * r3 <- this->class
3218 * r4 <- dPC
3219 * r7 <- this->class->vtable
3220 */
3221
3222 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003223 opRegReg(cUnit, OP_MOV, r9, r1);
3224 opRegReg(cUnit, OP_MOV, r10, r2);
3225 opRegReg(cUnit, OP_MOV, r12, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003226
Ben Chengba4fc8b2009-06-01 13:00:29 -07003227 /* r0 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003228 opRegReg(cUnit, OP_MOV, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003229
3230 /* r1 = BBBB */
3231 loadConstant(cUnit, r1, dInsn->vB);
3232
3233 /* r2 = method (caller) */
3234 loadConstant(cUnit, r2, (int) cUnit->method);
3235
3236 /* r3 = pDvmDex */
3237 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3238
3239 loadConstant(cUnit, r7,
3240 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003241 opReg(cUnit, OP_BLX, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003242
3243 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3244
Bill Buzbee270c1d62009-08-13 16:58:07 -07003245 opRegReg(cUnit, OP_MOV, r1, r9);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003246
Ben Cheng38329f52009-07-07 14:19:20 -07003247 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003248 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003249
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003250 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003251 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07003252
Bill Buzbee270c1d62009-08-13 16:58:07 -07003253 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3254 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003255
Bill Buzbee270c1d62009-08-13 16:58:07 -07003256 opRegReg(cUnit, OP_MOV, r2, r10);
3257 opRegReg(cUnit, OP_MOV, r3, r12);
Ben Cheng38329f52009-07-07 14:19:20 -07003258
3259 /*
3260 * r0 = calleeMethod
3261 * r2 = &predictedChainingCell
3262 * r3 = class
3263 *
3264 * &returnChainingCell has been loaded into r1 but is not needed
3265 * when patching the chaining cell and will be clobbered upon
3266 * returning so it will be reconstructed again.
3267 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003268 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003269
3270 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003271 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003272 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003273
3274 bypassRechaining->generic.target = (LIR *) addrRetChain;
3275
Ben Chengba4fc8b2009-06-01 13:00:29 -07003276 /*
3277 * r0 = this, r1 = calleeMethod,
3278 * r1 = &ChainingCell,
3279 * r4PC = callsiteDPC,
3280 */
3281 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3282#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003283 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003284#endif
3285 /* Handle exceptions using the interpreter */
3286 genTrap(cUnit, mir->offset, pcrLabel);
3287 break;
3288 }
3289 /* NOP */
3290 case OP_INVOKE_DIRECT_EMPTY: {
3291 return false;
3292 }
3293 case OP_FILLED_NEW_ARRAY:
3294 case OP_FILLED_NEW_ARRAY_RANGE: {
3295 /* Just let the interpreter deal with these */
3296 genInterpSingleStep(cUnit, mir);
3297 break;
3298 }
3299 default:
3300 return true;
3301 }
3302 return false;
3303}
3304
3305static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003306 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003307{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003308 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3309 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3310 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003311
3312 DecodedInstruction *dInsn = &mir->dalvikInsn;
3313 switch (mir->dalvikInsn.opCode) {
3314 /* calleeMethod = this->clazz->vtable[BBBB] */
3315 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3316 case OP_INVOKE_VIRTUAL_QUICK: {
3317 int methodIndex = dInsn->vB;
3318 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3319 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3320 else
3321 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3322
Ben Cheng38329f52009-07-07 14:19:20 -07003323 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3324 retChainingCell,
3325 predChainingCell,
3326 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003327 break;
3328 }
3329 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3330 case OP_INVOKE_SUPER_QUICK:
3331 case OP_INVOKE_SUPER_QUICK_RANGE: {
3332 const Method *calleeMethod =
3333 cUnit->method->clazz->super->vtable[dInsn->vB];
3334
3335 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3336 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3337 else
3338 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3339
3340 /* r0 = calleeMethod */
3341 loadConstant(cUnit, r0, (int) calleeMethod);
3342
Ben Cheng38329f52009-07-07 14:19:20 -07003343 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3344 calleeMethod);
3345 /* Handle exceptions using the interpreter */
3346 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003347 break;
3348 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003349 default:
3350 return true;
3351 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003352 return false;
3353}
3354
3355/*
3356 * NOTE: We assume here that the special native inline routines
3357 * are side-effect free. By making this assumption, we can safely
3358 * re-execute the routine from the interpreter if it decides it
3359 * wants to throw an exception. We still need to EXPORT_PC(), though.
3360 */
3361static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3362{
3363 DecodedInstruction *dInsn = &mir->dalvikInsn;
3364 switch( mir->dalvikInsn.opCode) {
3365 case OP_EXECUTE_INLINE: {
3366 unsigned int i;
3367 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003368 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003369 int operation = dInsn->vB;
3370
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003371 switch (operation) {
3372 case INLINE_EMPTYINLINEMETHOD:
3373 return false; /* Nop */
3374 case INLINE_STRING_LENGTH:
3375 return genInlinedStringLength(cUnit, mir);
3376 case INLINE_MATH_ABS_INT:
3377 return genInlinedAbsInt(cUnit, mir);
3378 case INLINE_MATH_ABS_LONG:
3379 return genInlinedAbsLong(cUnit, mir);
3380 case INLINE_MATH_MIN_INT:
3381 return genInlinedMinMaxInt(cUnit, mir, true);
3382 case INLINE_MATH_MAX_INT:
3383 return genInlinedMinMaxInt(cUnit, mir, false);
3384 case INLINE_STRING_CHARAT:
3385 return genInlinedStringCharAt(cUnit, mir);
3386 case INLINE_MATH_SQRT:
3387 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003388 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003389 else
3390 break; /* Handle with C routine */
3391 case INLINE_MATH_COS:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003392 case INLINE_MATH_SIN:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003393 break; /* Handle with C routine */
3394 case INLINE_MATH_ABS_FLOAT:
3395 return genInlinedAbsFloat(cUnit, mir);
3396 case INLINE_MATH_ABS_DOUBLE:
3397 return genInlinedAbsDouble(cUnit, mir);
3398 case INLINE_STRING_COMPARETO:
3399 case INLINE_STRING_EQUALS:
Bill Buzbee12ba0152009-09-03 14:03:09 -07003400 case INLINE_STRING_INDEXOF_I:
3401 case INLINE_STRING_INDEXOF_II:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003402 break;
3403 default:
3404 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003405 }
3406
3407 /* Materialize pointer to retval & push */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003408 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3409 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3410
Ben Chengba4fc8b2009-06-01 13:00:29 -07003411 /* Push r4 and (just to take up space) r5) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003412 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003413
3414 /* Get code pointer to inline routine */
3415 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3416
3417 /* Export PC */
3418 genExportPC(cUnit, mir, r0, r1 );
3419
3420 /* Load arguments to r0 through r3 as applicable */
3421 for (i=0; i < dInsn->vA; i++) {
3422 loadValue(cUnit, dInsn->arg[i], i);
3423 }
3424 /* Call inline routine */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003425 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003426
3427 /* Strip frame */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003428 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003429
3430 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003431 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003432
Ben Chenge9695e52009-06-16 16:11:47 -07003433 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003434 break;
3435 }
3436 default:
3437 return true;
3438 }
3439 return false;
3440}
3441
3442static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3443{
3444 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3445 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3446 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3447 return false;
3448}
3449
Ben Chengba4fc8b2009-06-01 13:00:29 -07003450/*
3451 * The following are special processing routines that handle transfer of
3452 * controls between compiled code and the interpreter. Certain VM states like
3453 * Dalvik PC and special-purpose registers are reconstructed here.
3454 */
3455
Ben Cheng1efc9c52009-06-08 18:25:27 -07003456/* Chaining cell for code that may need warmup. */
3457static void handleNormalChainingCell(CompilationUnit *cUnit,
3458 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003459{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003460 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3461 jitToInterpEntries.dvmJitToInterpNormal), r0);
3462 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003463 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3464}
3465
3466/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003467 * Chaining cell for instructions that immediately following already translated
3468 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003469 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003470static void handleHotChainingCell(CompilationUnit *cUnit,
3471 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003472{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003473 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3474 jitToInterpEntries.dvmJitToTraceSelect), r0);
3475 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003476 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3477}
3478
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003479#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003480/* Chaining cell for branches that branch back into the same basic block */
3481static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3482 unsigned int offset)
3483{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003484#if defined(WITH_SELF_VERIFICATION)
Jeff Hao97319a82009-08-12 16:57:15 -07003485 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3486 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003487#else
3488 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3489 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3490#endif
Jeff Hao97319a82009-08-12 16:57:15 -07003491 newLIR1(cUnit, THUMB_BLX_R, r0);
3492 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3493}
3494
3495#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003496/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003497static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3498 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003499{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003500 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3501 jitToInterpEntries.dvmJitToTraceSelect), r0);
3502 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003503 addWordData(cUnit, (int) (callee->insns), true);
3504}
3505
Ben Cheng38329f52009-07-07 14:19:20 -07003506/* Chaining cell for monomorphic method invocations. */
3507static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3508{
3509
3510 /* Should not be executed in the initial state */
3511 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3512 /* To be filled: class */
3513 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3514 /* To be filled: method */
3515 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3516 /*
3517 * Rechain count. The initial value of 0 here will trigger chaining upon
3518 * the first invocation of this callsite.
3519 */
3520 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3521}
3522
Ben Chengba4fc8b2009-06-01 13:00:29 -07003523/* Load the Dalvik PC into r0 and jump to the specified target */
3524static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003525 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003526{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003527 ArmLIR **pcrLabel =
3528 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003529 int numElems = cUnit->pcReconstructionList.numUsed;
3530 int i;
3531 for (i = 0; i < numElems; i++) {
3532 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3533 /* r0 = dalvik PC */
3534 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3535 genUnconditionalBranch(cUnit, targetLabel);
3536 }
3537}
3538
Ben Cheng4238ec22009-08-24 16:32:22 -07003539static char *extendedMIROpNames[MIR_OP_LAST - MIR_OP_FIRST] = {
3540 "MIR_OP_PHI",
3541 "MIR_OP_NULL_N_RANGE_UP_CHECK",
3542 "MIR_OP_NULL_N_RANGE_DOWN_CHECK",
3543 "MIR_OP_LOWER_BOUND_CHECK",
3544 "MIR_OP_PUNT",
3545};
3546
3547/*
3548 * vA = arrayReg;
3549 * vB = idxReg;
3550 * vC = endConditionReg;
3551 * arg[0] = maxC
3552 * arg[1] = minC
3553 * arg[2] = loopBranchConditionCode
3554 */
3555static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3556{
3557 DecodedInstruction *dInsn = &mir->dalvikInsn;
3558 const int lenOffset = offsetof(ArrayObject, length);
3559 const int regArray = 0;
3560 const int regIdxEnd = NEXT_REG(regArray);
3561 const int regLength = regArray;
3562 const int maxC = dInsn->arg[0];
3563 const int minC = dInsn->arg[1];
3564
3565 /* regArray <- arrayRef */
3566 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3567 loadValue(cUnit, mir->dalvikInsn.vC, regIdxEnd);
3568 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3569 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3570
3571 /* regLength <- len(arrayRef) */
3572 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3573
3574 int delta = maxC;
3575 /*
3576 * If the loop end condition is ">=" instead of ">", then the largest value
3577 * of the index is "endCondition - 1".
3578 */
3579 if (dInsn->arg[2] == OP_IF_GE) {
3580 delta--;
3581 }
3582
3583 if (delta) {
3584 opRegImm(cUnit, OP_ADD, regIdxEnd, delta, regIdxEnd);
3585 }
3586 /* Punt if "regIdxEnd < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003587 genRegRegCheck(cUnit, ARM_COND_GE, regIdxEnd, regLength, 0,
3588 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003589}
3590
3591/*
3592 * vA = arrayReg;
3593 * vB = idxReg;
3594 * vC = endConditionReg;
3595 * arg[0] = maxC
3596 * arg[1] = minC
3597 * arg[2] = loopBranchConditionCode
3598 */
3599static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3600{
3601 DecodedInstruction *dInsn = &mir->dalvikInsn;
3602 const int lenOffset = offsetof(ArrayObject, length);
3603 const int regArray = 0;
3604 const int regIdxInit = NEXT_REG(regArray);
3605 const int regLength = regArray;
3606 const int maxC = dInsn->arg[0];
3607 const int minC = dInsn->arg[1];
3608
3609 /* regArray <- arrayRef */
3610 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3611 loadValue(cUnit, mir->dalvikInsn.vB, regIdxInit);
3612 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3613 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3614
3615 /* regLength <- len(arrayRef) */
3616 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3617
3618 if (maxC) {
3619 opRegImm(cUnit, OP_ADD, regIdxInit, maxC, regIdxInit);
3620 }
3621
3622 /* Punt if "regIdxInit < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003623 genRegRegCheck(cUnit, ARM_COND_GE, regIdxInit, regLength, 0,
3624 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003625}
3626
3627/*
3628 * vA = idxReg;
3629 * vB = minC;
3630 */
3631static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3632{
3633 DecodedInstruction *dInsn = &mir->dalvikInsn;
3634 const int regIdx = 0;
3635 const int minC = dInsn->vB;
3636
3637 /* regIdx <- initial index value */
3638 loadValue(cUnit, mir->dalvikInsn.vA, regIdx);
3639
3640 /* Punt if "regIdxInit + minC >= 0" is false */
3641 genRegImmCheck(cUnit, ARM_COND_LT, regIdx, -minC, 0,
3642 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3643}
3644
3645/* Extended MIR instructions like PHI */
3646static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3647{
3648 int opOffset = mir->dalvikInsn.opCode - MIR_OP_FIRST;
3649 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3650 false);
3651 strcpy(msg, extendedMIROpNames[opOffset]);
3652 newLIR1(cUnit, ARM_PSEUDO_EXTENDED_MIR, (int) msg);
3653
3654 switch (mir->dalvikInsn.opCode) {
3655 case MIR_OP_PHI: {
3656 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3657 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3658 break;
3659 }
3660 case MIR_OP_NULL_N_RANGE_UP_CHECK: {
3661 genHoistedChecksForCountUpLoop(cUnit, mir);
3662 break;
3663 }
3664 case MIR_OP_NULL_N_RANGE_DOWN_CHECK: {
3665 genHoistedChecksForCountDownLoop(cUnit, mir);
3666 break;
3667 }
3668 case MIR_OP_LOWER_BOUND_CHECK: {
3669 genHoistedLowerBoundCheck(cUnit, mir);
3670 break;
3671 }
3672 case MIR_OP_PUNT: {
3673 genUnconditionalBranch(cUnit,
3674 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3675 break;
3676 }
3677 default:
3678 break;
3679 }
3680}
3681
3682/*
3683 * Create a PC-reconstruction cell for the starting offset of this trace.
3684 * Since the PCR cell is placed near the end of the compiled code which is
3685 * usually out of range for a conditional branch, we put two branches (one
3686 * branch over to the loop body and one layover branch to the actual PCR) at the
3687 * end of the entry block.
3688 */
3689static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3690 ArmLIR *bodyLabel)
3691{
3692 /* Set up the place holder to reconstruct this Dalvik PC */
3693 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3694 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
3695 pcrLabel->operands[0] =
3696 (int) (cUnit->method->insns + entry->startOffset);
3697 pcrLabel->operands[1] = entry->startOffset;
3698 /* Insert the place holder to the growable list */
3699 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3700
3701 /*
3702 * Next, create two branches - one branch over to the loop body and the
3703 * other branch to the PCR cell to punt.
3704 */
3705 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3706 branchToBody->opCode = THUMB_B_UNCOND;
3707 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003708 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07003709 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3710
3711 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3712 branchToPCR->opCode = THUMB_B_UNCOND;
3713 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003714 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003715 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3716}
3717
Ben Chengba4fc8b2009-06-01 13:00:29 -07003718void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3719{
3720 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003721 ArmLIR *labelList =
3722 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003723 GrowableList chainingListByType[CHAINING_CELL_LAST];
3724 int i;
3725
3726 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003727 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003728 */
3729 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3730 dvmInitGrowableList(&chainingListByType[i], 2);
3731 }
3732
3733 BasicBlock **blockList = cUnit->blockList;
3734
Bill Buzbee6e963e12009-06-17 16:56:19 -07003735 if (cUnit->executionCount) {
3736 /*
3737 * Reserve 6 bytes at the beginning of the trace
3738 * +----------------------------+
3739 * | execution count (4 bytes) |
3740 * +----------------------------+
3741 * | chain cell offset (2 bytes)|
3742 * +----------------------------+
3743 * ...and then code to increment the execution
3744 * count:
3745 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3746 * sub r0, #10 @ back up to addr of executionCount
3747 * ldr r1, [r0]
3748 * add r1, #1
3749 * str r1, [r0]
3750 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003751 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3752 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003753 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003754 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003755 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003756 /* Thumb instruction used directly here to ensure correct size */
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003757 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003758 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3759 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3760 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3761 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003762 } else {
3763 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003764 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003765 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003766 cUnit->headerSize = 2;
3767 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003768
Ben Chengba4fc8b2009-06-01 13:00:29 -07003769 /* Handle the content in each basic block */
3770 for (i = 0; i < cUnit->numBlocks; i++) {
3771 blockList[i]->visited = true;
3772 MIR *mir;
3773
3774 labelList[i].operands[0] = blockList[i]->startOffset;
3775
3776 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3777 /*
3778 * Append the label pseudo LIR first. Chaining cells will be handled
3779 * separately afterwards.
3780 */
3781 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3782 }
3783
Ben Cheng4238ec22009-08-24 16:32:22 -07003784 if (blockList[i]->blockType == ENTRY_BLOCK) {
3785 labelList[i].opCode = ARM_PSEUDO_ENTRY_BLOCK;
3786 if (blockList[i]->firstMIRInsn == NULL) {
3787 continue;
3788 } else {
3789 setupLoopEntryBlock(cUnit, blockList[i],
3790 &labelList[blockList[i]->fallThrough->id]);
3791 }
3792 } else if (blockList[i]->blockType == EXIT_BLOCK) {
3793 labelList[i].opCode = ARM_PSEUDO_EXIT_BLOCK;
3794 goto gen_fallthrough;
3795 } else if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003796 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003797 /* Reset the register state */
3798 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003799 } else {
3800 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003801 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003802 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003803 /* handle the codegen later */
3804 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003805 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003806 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003807 case CHAINING_CELL_INVOKE_SINGLETON:
3808 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003809 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003810 labelList[i].operands[0] =
3811 (int) blockList[i]->containingMethod;
3812 /* handle the codegen later */
3813 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003814 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3815 (void *) i);
3816 break;
3817 case CHAINING_CELL_INVOKE_PREDICTED:
3818 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003819 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003820 /* handle the codegen later */
3821 dvmInsertGrowableList(
3822 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3823 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003824 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003825 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003826 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003827 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003828 /* handle the codegen later */
3829 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003830 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003831 (void *) i);
3832 break;
3833 case PC_RECONSTRUCTION:
3834 /* Make sure exception handling block is next */
3835 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003836 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003837 assert (i == cUnit->numBlocks - 2);
3838 handlePCReconstruction(cUnit, &labelList[i+1]);
3839 break;
3840 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003841 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003842 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003843 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3844 jitToInterpEntries.dvmJitToInterpPunt),
3845 r1);
3846 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003847 }
3848 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003849#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003850 case CHAINING_CELL_BACKWARD_BRANCH:
3851 labelList[i].opCode =
3852 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3853 /* handle the codegen later */
3854 dvmInsertGrowableList(
3855 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3856 (void *) i);
3857 break;
3858#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003859 default:
3860 break;
3861 }
3862 continue;
3863 }
Ben Chenge9695e52009-06-16 16:11:47 -07003864
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003865 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003866
Ben Chengba4fc8b2009-06-01 13:00:29 -07003867 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003868 if (mir->dalvikInsn.opCode >= MIR_OP_FIRST) {
3869 handleExtendedMIR(cUnit, mir);
3870 continue;
3871 }
3872
Ben Chengba4fc8b2009-06-01 13:00:29 -07003873 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3874 InstructionFormat dalvikFormat =
3875 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003876 ArmLIR *boundaryLIR =
3877 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Cheng4238ec22009-08-24 16:32:22 -07003878 mir->offset, dalvikOpCode);
3879 if (mir->ssaRep) {
3880 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3881 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3882 }
3883
Ben Chenge9695e52009-06-16 16:11:47 -07003884 /* Remember the first LIR for this block */
3885 if (headLIR == NULL) {
3886 headLIR = boundaryLIR;
3887 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003888
Ben Chengba4fc8b2009-06-01 13:00:29 -07003889 bool notHandled;
3890 /*
3891 * Debugging: screen the opcode first to see if it is in the
3892 * do[-not]-compile list
3893 */
3894 bool singleStepMe =
3895 gDvmJit.includeSelectedOp !=
3896 ((gDvmJit.opList[dalvikOpCode >> 3] &
3897 (1 << (dalvikOpCode & 0x7))) !=
3898 0);
Jeff Hao97319a82009-08-12 16:57:15 -07003899#if defined(WITH_SELF_VERIFICATION)
3900 /* Punt on opcodes we can't replay */
3901 if (selfVerificationPuntOps(dalvikOpCode))
3902 singleStepMe = true;
3903#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003904 if (singleStepMe || cUnit->allSingleStep) {
3905 notHandled = false;
3906 genInterpSingleStep(cUnit, mir);
3907 } else {
3908 opcodeCoverage[dalvikOpCode]++;
3909 switch (dalvikFormat) {
3910 case kFmt10t:
3911 case kFmt20t:
3912 case kFmt30t:
3913 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3914 mir, blockList[i], labelList);
3915 break;
3916 case kFmt10x:
3917 notHandled = handleFmt10x(cUnit, mir);
3918 break;
3919 case kFmt11n:
3920 case kFmt31i:
3921 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3922 break;
3923 case kFmt11x:
3924 notHandled = handleFmt11x(cUnit, mir);
3925 break;
3926 case kFmt12x:
3927 notHandled = handleFmt12x(cUnit, mir);
3928 break;
3929 case kFmt20bc:
3930 notHandled = handleFmt20bc(cUnit, mir);
3931 break;
3932 case kFmt21c:
3933 case kFmt31c:
3934 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3935 break;
3936 case kFmt21h:
3937 notHandled = handleFmt21h(cUnit, mir);
3938 break;
3939 case kFmt21s:
3940 notHandled = handleFmt21s(cUnit, mir);
3941 break;
3942 case kFmt21t:
3943 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3944 labelList);
3945 break;
3946 case kFmt22b:
3947 case kFmt22s:
3948 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3949 break;
3950 case kFmt22c:
3951 notHandled = handleFmt22c(cUnit, mir);
3952 break;
3953 case kFmt22cs:
3954 notHandled = handleFmt22cs(cUnit, mir);
3955 break;
3956 case kFmt22t:
3957 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3958 labelList);
3959 break;
3960 case kFmt22x:
3961 case kFmt32x:
3962 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3963 break;
3964 case kFmt23x:
3965 notHandled = handleFmt23x(cUnit, mir);
3966 break;
3967 case kFmt31t:
3968 notHandled = handleFmt31t(cUnit, mir);
3969 break;
3970 case kFmt3rc:
3971 case kFmt35c:
3972 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3973 labelList);
3974 break;
3975 case kFmt3rms:
3976 case kFmt35ms:
3977 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3978 labelList);
3979 break;
3980 case kFmt3inline:
3981 notHandled = handleFmt3inline(cUnit, mir);
3982 break;
3983 case kFmt51l:
3984 notHandled = handleFmt51l(cUnit, mir);
3985 break;
3986 default:
3987 notHandled = true;
3988 break;
3989 }
3990 }
3991 if (notHandled) {
3992 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3993 mir->offset,
3994 dalvikOpCode, getOpcodeName(dalvikOpCode),
3995 dalvikFormat);
3996 dvmAbort();
3997 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003998 }
3999 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004000
4001 if (blockList[i]->blockType == ENTRY_BLOCK) {
4002 dvmCompilerAppendLIR(cUnit,
4003 (LIR *) cUnit->loopAnalysis->branchToBody);
4004 dvmCompilerAppendLIR(cUnit,
4005 (LIR *) cUnit->loopAnalysis->branchToPCR);
4006 }
4007
4008 if (headLIR) {
4009 /*
4010 * Eliminate redundant loads/stores and delay stores into later
4011 * slots
4012 */
4013 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4014 cUnit->lastLIRInsn);
4015 }
4016
4017gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004018 /*
4019 * Check if the block is terminated due to trace length constraint -
4020 * insert an unconditional branch to the chaining cell.
4021 */
4022 if (blockList[i]->needFallThroughBranch) {
4023 genUnconditionalBranch(cUnit,
4024 &labelList[blockList[i]->fallThrough->id]);
4025 }
4026
Ben Chengba4fc8b2009-06-01 13:00:29 -07004027 }
4028
Ben Chenge9695e52009-06-16 16:11:47 -07004029 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07004030 for (i = 0; i < CHAINING_CELL_LAST; i++) {
4031 size_t j;
4032 int *blockIdList = (int *) chainingListByType[i].elemList;
4033
4034 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4035
4036 /* No chaining cells of this type */
4037 if (cUnit->numChainingCells[i] == 0)
4038 continue;
4039
4040 /* Record the first LIR for a new type of chaining cell */
4041 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4042
4043 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4044 int blockId = blockIdList[j];
4045
4046 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004047 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004048
4049 /* Insert the pseudo chaining instruction */
4050 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4051
4052
4053 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07004054 case CHAINING_CELL_NORMAL:
4055 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004056 blockList[blockId]->startOffset);
4057 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004058 case CHAINING_CELL_INVOKE_SINGLETON:
4059 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004060 blockList[blockId]->containingMethod);
4061 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004062 case CHAINING_CELL_INVOKE_PREDICTED:
4063 handleInvokePredictedChainingCell(cUnit);
4064 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07004065 case CHAINING_CELL_HOT:
4066 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004067 blockList[blockId]->startOffset);
4068 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004069#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07004070 case CHAINING_CELL_BACKWARD_BRANCH:
4071 handleBackwardBranchChainingCell(cUnit,
4072 blockList[blockId]->startOffset);
4073 break;
4074#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004075 default:
4076 dvmAbort();
4077 break;
4078 }
4079 }
4080 }
Ben Chenge9695e52009-06-16 16:11:47 -07004081
4082 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004083}
4084
4085/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004086bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004087{
Bill Buzbee716f1202009-07-23 13:22:09 -07004088 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004089
4090 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07004091 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004092 }
4093
4094 switch (work->kind) {
4095 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07004096 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004097 break;
4098 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004099 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07004100 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004101 break;
4102 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07004103 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004104 dvmAbort();
4105 }
4106 return res;
4107}
4108
Ben Chengba4fc8b2009-06-01 13:00:29 -07004109/* Architectural-specific debugging helpers go here */
4110void dvmCompilerArchDump(void)
4111{
4112 /* Print compiled opcode in this VM instance */
4113 int i, start, streak;
4114 char buf[1024];
4115
4116 streak = i = 0;
4117 buf[0] = 0;
4118 while (opcodeCoverage[i] == 0 && i < 256) {
4119 i++;
4120 }
4121 if (i == 256) {
4122 return;
4123 }
4124 for (start = i++, streak = 1; i < 256; i++) {
4125 if (opcodeCoverage[i]) {
4126 streak++;
4127 } else {
4128 if (streak == 1) {
4129 sprintf(buf+strlen(buf), "%x,", start);
4130 } else {
4131 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4132 }
4133 streak = 0;
4134 while (opcodeCoverage[i] == 0 && i < 256) {
4135 i++;
4136 }
4137 if (i < 256) {
4138 streak = 1;
4139 start = i;
4140 }
4141 }
4142 }
4143 if (streak) {
4144 if (streak == 1) {
4145 sprintf(buf+strlen(buf), "%x", start);
4146 } else {
4147 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4148 }
4149 }
4150 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004151 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004152 }
4153}