blob: 30dc508e52aefc1fe4f801eaae2e1b777736197f [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 Buzbeea6f40f12009-09-22 09:45:41 -07002643 if (lit != 0) {
2644 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2645 storeValue(cUnit, regDest, vDest, reg1);
2646 } else {
2647 storeValue(cUnit, reg0, vDest, reg1);
2648 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002649 break;
2650
2651 case OP_DIV_INT_LIT8:
2652 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002653 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002654 if (lit == 0) {
2655 /* Let the interpreter deal with div by 0 */
2656 genInterpSingleStep(cUnit, mir);
2657 return false;
2658 }
2659 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2660 loadConstant(cUnit, r1, lit);
2661 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002662 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002663 storeValue(cUnit, r0, vDest, r2);
2664 break;
2665
2666 case OP_REM_INT_LIT8:
2667 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002668 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002669 if (lit == 0) {
2670 /* Let the interpreter deal with div by 0 */
2671 genInterpSingleStep(cUnit, mir);
2672 return false;
2673 }
2674 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2675 loadConstant(cUnit, r1, lit);
2676 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002677 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002678 storeValue(cUnit, r1, vDest, r2);
2679 break;
2680 default:
2681 return true;
2682 }
2683 return false;
2684}
2685
2686static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2687{
2688 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2689 int fieldOffset;
2690
2691 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2692 InstField *pInstField = (InstField *)
2693 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2694 int fieldOffset;
2695
2696 assert(pInstField != NULL);
2697 fieldOffset = pInstField->byteOffset;
2698 } else {
2699 /* To make the compiler happy */
2700 fieldOffset = 0;
2701 }
2702 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002703 case OP_NEW_ARRAY: {
2704 void *classPtr = (void*)
2705 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2706 assert(classPtr != NULL);
2707 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2708 loadConstant(cUnit, r0, (int) classPtr );
2709 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002710 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002711 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2712 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002713 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2714 opReg(cUnit, OP_BLX, r4PC);
2715 /* Note: on failure, we'll bail and reinterpret */
Ben Chenge9695e52009-06-16 16:11:47 -07002716 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002717 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2718 break;
2719 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002720 case OP_INSTANCE_OF: {
2721 ClassObject *classPtr =
2722 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2723 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002724 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002725 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002726//TUNING: compare to 0 primative to allow use of CB[N]Z
2727 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002728 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002729 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002730 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002731 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002732 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002733 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002734 opRegReg(cUnit, OP_CMP, r1, r2);
2735 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2736 opRegReg(cUnit, OP_MOV, r0, r1);
2737 opRegReg(cUnit, OP_MOV, r1, r2);
2738 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002739 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002740 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002741 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2742 branch1->generic.target = (LIR *)target;
2743 branch2->generic.target = (LIR *)target;
2744 break;
2745 }
2746 case OP_IGET_WIDE:
2747 genIGetWide(cUnit, mir, fieldOffset);
2748 break;
2749 case OP_IGET:
2750 case OP_IGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002751 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002752 break;
2753 case OP_IGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002754 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002755 break;
2756 case OP_IGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002757 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002758 break;
2759 case OP_IGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002760 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002761 break;
2762 case OP_IGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002763 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002764 break;
2765 case OP_IPUT_WIDE:
2766 genIPutWide(cUnit, mir, fieldOffset);
2767 break;
2768 case OP_IPUT:
2769 case OP_IPUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002770 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002771 break;
2772 case OP_IPUT_SHORT:
2773 case OP_IPUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002774 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002775 break;
2776 case OP_IPUT_BYTE:
2777 case OP_IPUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002778 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002779 break;
2780 default:
2781 return true;
2782 }
2783 return false;
2784}
2785
2786static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2787{
2788 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2789 int fieldOffset = mir->dalvikInsn.vC;
2790 switch (dalvikOpCode) {
2791 case OP_IGET_QUICK:
2792 case OP_IGET_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002793 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002794 break;
2795 case OP_IPUT_QUICK:
2796 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002797 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002798 break;
2799 case OP_IGET_WIDE_QUICK:
2800 genIGetWide(cUnit, mir, fieldOffset);
2801 break;
2802 case OP_IPUT_WIDE_QUICK:
2803 genIPutWide(cUnit, mir, fieldOffset);
2804 break;
2805 default:
2806 return true;
2807 }
2808 return false;
2809
2810}
2811
2812/* Compare agaist zero */
2813static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002814 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002815{
2816 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002817 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002818 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002819
Ben Chenge9695e52009-06-16 16:11:47 -07002820 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2821 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2822 reg1 = NEXT_REG(reg0);
2823 /* Load vB first since vA can be fetched via a move */
2824 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2825 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2826 } else {
2827 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2828 reg1 = NEXT_REG(reg0);
2829 /* Load vA first since vB can be fetched via a move */
2830 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2831 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2832 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002833 opRegReg(cUnit, OP_CMP, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002834
2835 switch (dalvikOpCode) {
2836 case OP_IF_EQ:
2837 cond = ARM_COND_EQ;
2838 break;
2839 case OP_IF_NE:
2840 cond = ARM_COND_NE;
2841 break;
2842 case OP_IF_LT:
2843 cond = ARM_COND_LT;
2844 break;
2845 case OP_IF_GE:
2846 cond = ARM_COND_GE;
2847 break;
2848 case OP_IF_GT:
2849 cond = ARM_COND_GT;
2850 break;
2851 case OP_IF_LE:
2852 cond = ARM_COND_LE;
2853 break;
2854 default:
2855 cond = 0;
2856 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2857 dvmAbort();
2858 }
2859 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2860 /* This mostly likely will be optimized away in a later phase */
2861 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2862 return false;
2863}
2864
2865static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2866{
2867 OpCode opCode = mir->dalvikInsn.opCode;
2868 int vSrc1Dest = mir->dalvikInsn.vA;
2869 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002870 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002871
2872 switch (opCode) {
2873 case OP_MOVE_16:
2874 case OP_MOVE_OBJECT_16:
2875 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002876 case OP_MOVE_OBJECT_FROM16: {
2877 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2878 reg1 = NEXT_REG(reg0);
2879 loadValue(cUnit, vSrc2, reg0);
2880 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002881 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002882 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002883 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002884 case OP_MOVE_WIDE_FROM16: {
2885 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2886 reg1 = NEXT_REG(reg0);
2887 reg2 = NEXT_REG(reg1);
2888 loadValuePair(cUnit, vSrc2, reg0, reg1);
2889 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002890 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002891 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002892 default:
2893 return true;
2894 }
2895 return false;
2896}
2897
2898static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2899{
2900 OpCode opCode = mir->dalvikInsn.opCode;
2901 int vA = mir->dalvikInsn.vA;
2902 int vB = mir->dalvikInsn.vB;
2903 int vC = mir->dalvikInsn.vC;
2904
Ben Chenge9695e52009-06-16 16:11:47 -07002905 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002906 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2907 return genArithOp( cUnit, mir );
2908 }
2909
2910 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002911 case OP_CMPL_FLOAT:
2912 case OP_CMPG_FLOAT:
2913 case OP_CMPL_DOUBLE:
2914 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002915 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002916 case OP_CMP_LONG:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07002917 genCmpLong(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002918 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002919 case OP_AGET_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002920 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002921 break;
2922 case OP_AGET:
2923 case OP_AGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002924 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002925 break;
2926 case OP_AGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002927 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002928 break;
2929 case OP_AGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002930 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002931 break;
2932 case OP_AGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002933 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002934 break;
2935 case OP_AGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002936 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002937 break;
2938 case OP_APUT_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002939 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002940 break;
2941 case OP_APUT:
2942 case OP_APUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002943 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002944 break;
2945 case OP_APUT_SHORT:
2946 case OP_APUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002947 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002948 break;
2949 case OP_APUT_BYTE:
2950 case OP_APUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002951 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002952 break;
2953 default:
2954 return true;
2955 }
2956 return false;
2957}
2958
2959static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2960{
2961 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2962 switch (dalvikOpCode) {
2963 case OP_FILL_ARRAY_DATA: {
2964 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2965 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2966 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2967 (int) (cUnit->method->insns + mir->offset));
2968 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002969 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002970 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002971 break;
2972 }
2973 /*
2974 * TODO
2975 * - Add a 1 to 3-entry per-location cache here to completely
2976 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2977 * - Use out-of-line handlers for both of these
2978 */
2979 case OP_PACKED_SWITCH:
2980 case OP_SPARSE_SWITCH: {
2981 if (dalvikOpCode == OP_PACKED_SWITCH) {
2982 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2983 } else {
2984 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2985 }
2986 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2987 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2988 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002989 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002990 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002991 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2992 jitToInterpEntries.dvmJitToInterpNoChain), r2);
2993 opRegReg(cUnit, OP_ADD, r0, r0);
2994 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
2995 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002996 break;
2997 }
2998 default:
2999 return true;
3000 }
3001 return false;
3002}
3003
3004static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003005 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003006{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003007 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003008 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003009
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003010 if (bb->fallThrough != NULL)
3011 retChainingCell = &labelList[bb->fallThrough->id];
3012
Ben Chengba4fc8b2009-06-01 13:00:29 -07003013 DecodedInstruction *dInsn = &mir->dalvikInsn;
3014 switch (mir->dalvikInsn.opCode) {
3015 /*
3016 * calleeMethod = this->clazz->vtable[
3017 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3018 * ]
3019 */
3020 case OP_INVOKE_VIRTUAL:
3021 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003022 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003023 int methodIndex =
3024 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3025 methodIndex;
3026
3027 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3028 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3029 else
3030 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3031
Ben Cheng38329f52009-07-07 14:19:20 -07003032 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3033 retChainingCell,
3034 predChainingCell,
3035 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003036 break;
3037 }
3038 /*
3039 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3040 * ->pResMethods[BBBB]->methodIndex]
3041 */
3042 /* TODO - not excersized in RunPerf.jar */
3043 case OP_INVOKE_SUPER:
3044 case OP_INVOKE_SUPER_RANGE: {
3045 int mIndex = cUnit->method->clazz->pDvmDex->
3046 pResMethods[dInsn->vB]->methodIndex;
3047 const Method *calleeMethod =
3048 cUnit->method->clazz->super->vtable[mIndex];
3049
3050 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3051 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3052 else
3053 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3054
3055 /* r0 = calleeMethod */
3056 loadConstant(cUnit, r0, (int) calleeMethod);
3057
Ben Cheng38329f52009-07-07 14:19:20 -07003058 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3059 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003060 break;
3061 }
3062 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3063 case OP_INVOKE_DIRECT:
3064 case OP_INVOKE_DIRECT_RANGE: {
3065 const Method *calleeMethod =
3066 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3067
3068 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3069 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3070 else
3071 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3072
3073 /* r0 = calleeMethod */
3074 loadConstant(cUnit, r0, (int) calleeMethod);
3075
Ben Cheng38329f52009-07-07 14:19:20 -07003076 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3077 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003078 break;
3079 }
3080 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3081 case OP_INVOKE_STATIC:
3082 case OP_INVOKE_STATIC_RANGE: {
3083 const Method *calleeMethod =
3084 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3085
3086 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3087 genProcessArgsNoRange(cUnit, mir, dInsn,
3088 NULL /* no null check */);
3089 else
3090 genProcessArgsRange(cUnit, mir, dInsn,
3091 NULL /* no null check */);
3092
3093 /* r0 = calleeMethod */
3094 loadConstant(cUnit, r0, (int) calleeMethod);
3095
Ben Cheng38329f52009-07-07 14:19:20 -07003096 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3097 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003098 break;
3099 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07003100/*
3101 * TODO: When we move to using upper registers in Thumb2, make sure
3102 * the register allocater is told that r9, r10, & r12 are killed
3103 * here.
3104 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003105 /*
3106 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3107 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003108 *
3109 * Given "invoke-interface {v0}", the following is the generated code:
3110 *
3111 * 0x426a9abe : ldr r0, [r5, #0] --+
3112 * 0x426a9ac0 : mov r7, r5 |
3113 * 0x426a9ac2 : sub r7, #24 |
3114 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3115 * 0x426a9ac6 : beq 0x426a9afe |
3116 * 0x426a9ac8 : stmia r7, <r0> --+
3117 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3118 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3119 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3120 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3121 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3122 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3123 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
3124 * 0x426a9ad8 : mov r9, r1 --+
3125 * 0x426a9ada : mov r10, r2 |
3126 * 0x426a9adc : mov r12, r3 |
3127 * 0x426a9ade : mov r0, r3 |
3128 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3129 * 0x426a9ae2 : ldr r2, [pc, #76] |
3130 * 0x426a9ae4 : ldr r3, [pc, #68] |
3131 * 0x426a9ae6 : ldr r7, [pc, #64] |
3132 * 0x426a9ae8 : blx r7 --+
3133 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
3134 * 0x426a9aec : cmp r1, #0 --> compare against 0
3135 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3136 * 0x426a9af0 : ldr r7, [r6, #96] --+
3137 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3138 * 0x426a9af4 : mov r3, r12 |
3139 * 0x426a9af6 : blx r7 --+
3140 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3141 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3142 * 0x426a9afc : blx_2 see above --+
3143 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3144 * 0x426a9afe (0042): ldr r0, [pc, #52]
3145 * Exception_Handling:
3146 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3147 * 0x426a9b02 (0046): blx r1
3148 * 0x426a9b04 (0048): .align4
3149 * -------- chaining cell (hot): 0x0021
3150 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3151 * 0x426a9b06 (004a): blx r0
3152 * 0x426a9b08 (004c): data 0x7872(30834)
3153 * 0x426a9b0a (004e): data 0x428b(17035)
3154 * 0x426a9b0c (0050): .align4
3155 * -------- chaining cell (predicted)
3156 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3157 * 0x426a9b0e (0052): data 0x0000(0)
3158 * 0x426a9b10 (0054): data 0x0000(0) --> class
3159 * 0x426a9b12 (0056): data 0x0000(0)
3160 * 0x426a9b14 (0058): data 0x0000(0) --> method
3161 * 0x426a9b16 (005a): data 0x0000(0)
3162 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3163 * 0x426a9b1a (005e): data 0x0000(0)
3164 * 0x426a9b28 (006c): .word (0xad0392a5)
3165 * 0x426a9b2c (0070): .word (0x6e750)
3166 * 0x426a9b30 (0074): .word (0x4109a618)
3167 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003168 */
3169 case OP_INVOKE_INTERFACE:
3170 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003171 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003172 int methodIndex = dInsn->vB;
3173
3174 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3175 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3176 else
3177 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3178
Ben Cheng38329f52009-07-07 14:19:20 -07003179 /* "this" is already left in r0 by genProcessArgs* */
3180
3181 /* r4PC = dalvikCallsite */
3182 loadConstant(cUnit, r4PC,
3183 (int) (cUnit->method->insns + mir->offset));
3184
3185 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003186 ArmLIR *addrRetChain =
3187 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003188 addrRetChain->generic.target = (LIR *) retChainingCell;
3189
3190 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003191 ArmLIR *predictedChainingCell =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003192 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003193 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3194
3195 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3196
3197 /* return through lr - jump to the chaining cell */
3198 genUnconditionalBranch(cUnit, predChainingCell);
3199
3200 /*
3201 * null-check on "this" may have been eliminated, but we still need
3202 * a PC-reconstruction label for stack overflow bailout.
3203 */
3204 if (pcrLabel == NULL) {
3205 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003206 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3207 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003208 pcrLabel->operands[0] = dPC;
3209 pcrLabel->operands[1] = mir->offset;
3210 /* Insert the place holder to the growable list */
3211 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3212 }
3213
3214 /* return through lr+2 - punt to the interpreter */
3215 genUnconditionalBranch(cUnit, pcrLabel);
3216
3217 /*
3218 * return through lr+4 - fully resolve the callee method.
3219 * r1 <- count
3220 * r2 <- &predictedChainCell
3221 * r3 <- this->class
3222 * r4 <- dPC
3223 * r7 <- this->class->vtable
3224 */
3225
3226 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003227 opRegReg(cUnit, OP_MOV, r9, r1);
3228 opRegReg(cUnit, OP_MOV, r10, r2);
3229 opRegReg(cUnit, OP_MOV, r12, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003230
Ben Chengba4fc8b2009-06-01 13:00:29 -07003231 /* r0 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003232 opRegReg(cUnit, OP_MOV, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003233
3234 /* r1 = BBBB */
3235 loadConstant(cUnit, r1, dInsn->vB);
3236
3237 /* r2 = method (caller) */
3238 loadConstant(cUnit, r2, (int) cUnit->method);
3239
3240 /* r3 = pDvmDex */
3241 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3242
3243 loadConstant(cUnit, r7,
3244 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003245 opReg(cUnit, OP_BLX, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003246
3247 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3248
Bill Buzbee270c1d62009-08-13 16:58:07 -07003249 opRegReg(cUnit, OP_MOV, r1, r9);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003250
Ben Cheng38329f52009-07-07 14:19:20 -07003251 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003252 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003253
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003254 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003255 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07003256
Bill Buzbee270c1d62009-08-13 16:58:07 -07003257 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3258 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003259
Bill Buzbee270c1d62009-08-13 16:58:07 -07003260 opRegReg(cUnit, OP_MOV, r2, r10);
3261 opRegReg(cUnit, OP_MOV, r3, r12);
Ben Cheng38329f52009-07-07 14:19:20 -07003262
3263 /*
3264 * r0 = calleeMethod
3265 * r2 = &predictedChainingCell
3266 * r3 = class
3267 *
3268 * &returnChainingCell has been loaded into r1 but is not needed
3269 * when patching the chaining cell and will be clobbered upon
3270 * returning so it will be reconstructed again.
3271 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003272 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003273
3274 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003275 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003276 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003277
3278 bypassRechaining->generic.target = (LIR *) addrRetChain;
3279
Ben Chengba4fc8b2009-06-01 13:00:29 -07003280 /*
3281 * r0 = this, r1 = calleeMethod,
3282 * r1 = &ChainingCell,
3283 * r4PC = callsiteDPC,
3284 */
3285 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3286#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003287 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003288#endif
3289 /* Handle exceptions using the interpreter */
3290 genTrap(cUnit, mir->offset, pcrLabel);
3291 break;
3292 }
3293 /* NOP */
3294 case OP_INVOKE_DIRECT_EMPTY: {
3295 return false;
3296 }
3297 case OP_FILLED_NEW_ARRAY:
3298 case OP_FILLED_NEW_ARRAY_RANGE: {
3299 /* Just let the interpreter deal with these */
3300 genInterpSingleStep(cUnit, mir);
3301 break;
3302 }
3303 default:
3304 return true;
3305 }
3306 return false;
3307}
3308
3309static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003310 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003311{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003312 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3313 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3314 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003315
3316 DecodedInstruction *dInsn = &mir->dalvikInsn;
3317 switch (mir->dalvikInsn.opCode) {
3318 /* calleeMethod = this->clazz->vtable[BBBB] */
3319 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3320 case OP_INVOKE_VIRTUAL_QUICK: {
3321 int methodIndex = dInsn->vB;
3322 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3323 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3324 else
3325 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3326
Ben Cheng38329f52009-07-07 14:19:20 -07003327 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3328 retChainingCell,
3329 predChainingCell,
3330 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003331 break;
3332 }
3333 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3334 case OP_INVOKE_SUPER_QUICK:
3335 case OP_INVOKE_SUPER_QUICK_RANGE: {
3336 const Method *calleeMethod =
3337 cUnit->method->clazz->super->vtable[dInsn->vB];
3338
3339 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3340 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3341 else
3342 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3343
3344 /* r0 = calleeMethod */
3345 loadConstant(cUnit, r0, (int) calleeMethod);
3346
Ben Cheng38329f52009-07-07 14:19:20 -07003347 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3348 calleeMethod);
3349 /* Handle exceptions using the interpreter */
3350 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003351 break;
3352 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003353 default:
3354 return true;
3355 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003356 return false;
3357}
3358
3359/*
3360 * NOTE: We assume here that the special native inline routines
3361 * are side-effect free. By making this assumption, we can safely
3362 * re-execute the routine from the interpreter if it decides it
3363 * wants to throw an exception. We still need to EXPORT_PC(), though.
3364 */
3365static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3366{
3367 DecodedInstruction *dInsn = &mir->dalvikInsn;
3368 switch( mir->dalvikInsn.opCode) {
3369 case OP_EXECUTE_INLINE: {
3370 unsigned int i;
3371 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003372 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003373 int operation = dInsn->vB;
3374
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003375 switch (operation) {
3376 case INLINE_EMPTYINLINEMETHOD:
3377 return false; /* Nop */
3378 case INLINE_STRING_LENGTH:
3379 return genInlinedStringLength(cUnit, mir);
3380 case INLINE_MATH_ABS_INT:
3381 return genInlinedAbsInt(cUnit, mir);
3382 case INLINE_MATH_ABS_LONG:
3383 return genInlinedAbsLong(cUnit, mir);
3384 case INLINE_MATH_MIN_INT:
3385 return genInlinedMinMaxInt(cUnit, mir, true);
3386 case INLINE_MATH_MAX_INT:
3387 return genInlinedMinMaxInt(cUnit, mir, false);
3388 case INLINE_STRING_CHARAT:
3389 return genInlinedStringCharAt(cUnit, mir);
3390 case INLINE_MATH_SQRT:
3391 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003392 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003393 else
3394 break; /* Handle with C routine */
3395 case INLINE_MATH_COS:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003396 case INLINE_MATH_SIN:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003397 break; /* Handle with C routine */
3398 case INLINE_MATH_ABS_FLOAT:
3399 return genInlinedAbsFloat(cUnit, mir);
3400 case INLINE_MATH_ABS_DOUBLE:
3401 return genInlinedAbsDouble(cUnit, mir);
3402 case INLINE_STRING_COMPARETO:
3403 case INLINE_STRING_EQUALS:
Bill Buzbee12ba0152009-09-03 14:03:09 -07003404 case INLINE_STRING_INDEXOF_I:
3405 case INLINE_STRING_INDEXOF_II:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003406 break;
3407 default:
3408 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003409 }
3410
3411 /* Materialize pointer to retval & push */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003412 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3413 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3414
Ben Chengba4fc8b2009-06-01 13:00:29 -07003415 /* Push r4 and (just to take up space) r5) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003416 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003417
3418 /* Get code pointer to inline routine */
3419 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3420
3421 /* Export PC */
3422 genExportPC(cUnit, mir, r0, r1 );
3423
3424 /* Load arguments to r0 through r3 as applicable */
3425 for (i=0; i < dInsn->vA; i++) {
3426 loadValue(cUnit, dInsn->arg[i], i);
3427 }
3428 /* Call inline routine */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003429 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003430
3431 /* Strip frame */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003432 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003433
3434 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003435 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003436
Ben Chenge9695e52009-06-16 16:11:47 -07003437 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003438 break;
3439 }
3440 default:
3441 return true;
3442 }
3443 return false;
3444}
3445
3446static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3447{
3448 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3449 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3450 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3451 return false;
3452}
3453
Ben Chengba4fc8b2009-06-01 13:00:29 -07003454/*
3455 * The following are special processing routines that handle transfer of
3456 * controls between compiled code and the interpreter. Certain VM states like
3457 * Dalvik PC and special-purpose registers are reconstructed here.
3458 */
3459
Ben Cheng1efc9c52009-06-08 18:25:27 -07003460/* Chaining cell for code that may need warmup. */
3461static void handleNormalChainingCell(CompilationUnit *cUnit,
3462 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003463{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003464 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3465 jitToInterpEntries.dvmJitToInterpNormal), r0);
3466 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003467 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3468}
3469
3470/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003471 * Chaining cell for instructions that immediately following already translated
3472 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003473 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003474static void handleHotChainingCell(CompilationUnit *cUnit,
3475 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003476{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003477 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3478 jitToInterpEntries.dvmJitToTraceSelect), r0);
3479 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003480 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3481}
3482
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003483#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003484/* Chaining cell for branches that branch back into the same basic block */
3485static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3486 unsigned int offset)
3487{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003488#if defined(WITH_SELF_VERIFICATION)
Jeff Hao97319a82009-08-12 16:57:15 -07003489 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3490 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003491#else
3492 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3493 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3494#endif
Jeff Hao97319a82009-08-12 16:57:15 -07003495 newLIR1(cUnit, THUMB_BLX_R, r0);
3496 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3497}
3498
3499#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003500/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003501static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3502 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003503{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003504 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3505 jitToInterpEntries.dvmJitToTraceSelect), r0);
3506 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003507 addWordData(cUnit, (int) (callee->insns), true);
3508}
3509
Ben Cheng38329f52009-07-07 14:19:20 -07003510/* Chaining cell for monomorphic method invocations. */
3511static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3512{
3513
3514 /* Should not be executed in the initial state */
3515 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3516 /* To be filled: class */
3517 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3518 /* To be filled: method */
3519 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3520 /*
3521 * Rechain count. The initial value of 0 here will trigger chaining upon
3522 * the first invocation of this callsite.
3523 */
3524 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3525}
3526
Ben Chengba4fc8b2009-06-01 13:00:29 -07003527/* Load the Dalvik PC into r0 and jump to the specified target */
3528static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003529 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003530{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003531 ArmLIR **pcrLabel =
3532 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003533 int numElems = cUnit->pcReconstructionList.numUsed;
3534 int i;
3535 for (i = 0; i < numElems; i++) {
3536 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3537 /* r0 = dalvik PC */
3538 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3539 genUnconditionalBranch(cUnit, targetLabel);
3540 }
3541}
3542
Ben Cheng4238ec22009-08-24 16:32:22 -07003543static char *extendedMIROpNames[MIR_OP_LAST - MIR_OP_FIRST] = {
3544 "MIR_OP_PHI",
3545 "MIR_OP_NULL_N_RANGE_UP_CHECK",
3546 "MIR_OP_NULL_N_RANGE_DOWN_CHECK",
3547 "MIR_OP_LOWER_BOUND_CHECK",
3548 "MIR_OP_PUNT",
3549};
3550
3551/*
3552 * vA = arrayReg;
3553 * vB = idxReg;
3554 * vC = endConditionReg;
3555 * arg[0] = maxC
3556 * arg[1] = minC
3557 * arg[2] = loopBranchConditionCode
3558 */
3559static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3560{
3561 DecodedInstruction *dInsn = &mir->dalvikInsn;
3562 const int lenOffset = offsetof(ArrayObject, length);
3563 const int regArray = 0;
3564 const int regIdxEnd = NEXT_REG(regArray);
3565 const int regLength = regArray;
3566 const int maxC = dInsn->arg[0];
3567 const int minC = dInsn->arg[1];
3568
3569 /* regArray <- arrayRef */
3570 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3571 loadValue(cUnit, mir->dalvikInsn.vC, regIdxEnd);
3572 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3573 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3574
3575 /* regLength <- len(arrayRef) */
3576 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3577
3578 int delta = maxC;
3579 /*
3580 * If the loop end condition is ">=" instead of ">", then the largest value
3581 * of the index is "endCondition - 1".
3582 */
3583 if (dInsn->arg[2] == OP_IF_GE) {
3584 delta--;
3585 }
3586
3587 if (delta) {
3588 opRegImm(cUnit, OP_ADD, regIdxEnd, delta, regIdxEnd);
3589 }
3590 /* Punt if "regIdxEnd < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003591 genRegRegCheck(cUnit, ARM_COND_GE, regIdxEnd, regLength, 0,
3592 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003593}
3594
3595/*
3596 * vA = arrayReg;
3597 * vB = idxReg;
3598 * vC = endConditionReg;
3599 * arg[0] = maxC
3600 * arg[1] = minC
3601 * arg[2] = loopBranchConditionCode
3602 */
3603static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3604{
3605 DecodedInstruction *dInsn = &mir->dalvikInsn;
3606 const int lenOffset = offsetof(ArrayObject, length);
3607 const int regArray = 0;
3608 const int regIdxInit = NEXT_REG(regArray);
3609 const int regLength = regArray;
3610 const int maxC = dInsn->arg[0];
3611 const int minC = dInsn->arg[1];
3612
3613 /* regArray <- arrayRef */
3614 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3615 loadValue(cUnit, mir->dalvikInsn.vB, regIdxInit);
3616 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3617 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3618
3619 /* regLength <- len(arrayRef) */
3620 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3621
3622 if (maxC) {
3623 opRegImm(cUnit, OP_ADD, regIdxInit, maxC, regIdxInit);
3624 }
3625
3626 /* Punt if "regIdxInit < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003627 genRegRegCheck(cUnit, ARM_COND_GE, regIdxInit, regLength, 0,
3628 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003629}
3630
3631/*
3632 * vA = idxReg;
3633 * vB = minC;
3634 */
3635static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3636{
3637 DecodedInstruction *dInsn = &mir->dalvikInsn;
3638 const int regIdx = 0;
3639 const int minC = dInsn->vB;
3640
3641 /* regIdx <- initial index value */
3642 loadValue(cUnit, mir->dalvikInsn.vA, regIdx);
3643
3644 /* Punt if "regIdxInit + minC >= 0" is false */
3645 genRegImmCheck(cUnit, ARM_COND_LT, regIdx, -minC, 0,
3646 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3647}
3648
3649/* Extended MIR instructions like PHI */
3650static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3651{
3652 int opOffset = mir->dalvikInsn.opCode - MIR_OP_FIRST;
3653 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3654 false);
3655 strcpy(msg, extendedMIROpNames[opOffset]);
3656 newLIR1(cUnit, ARM_PSEUDO_EXTENDED_MIR, (int) msg);
3657
3658 switch (mir->dalvikInsn.opCode) {
3659 case MIR_OP_PHI: {
3660 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3661 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3662 break;
3663 }
3664 case MIR_OP_NULL_N_RANGE_UP_CHECK: {
3665 genHoistedChecksForCountUpLoop(cUnit, mir);
3666 break;
3667 }
3668 case MIR_OP_NULL_N_RANGE_DOWN_CHECK: {
3669 genHoistedChecksForCountDownLoop(cUnit, mir);
3670 break;
3671 }
3672 case MIR_OP_LOWER_BOUND_CHECK: {
3673 genHoistedLowerBoundCheck(cUnit, mir);
3674 break;
3675 }
3676 case MIR_OP_PUNT: {
3677 genUnconditionalBranch(cUnit,
3678 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3679 break;
3680 }
3681 default:
3682 break;
3683 }
3684}
3685
3686/*
3687 * Create a PC-reconstruction cell for the starting offset of this trace.
3688 * Since the PCR cell is placed near the end of the compiled code which is
3689 * usually out of range for a conditional branch, we put two branches (one
3690 * branch over to the loop body and one layover branch to the actual PCR) at the
3691 * end of the entry block.
3692 */
3693static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3694 ArmLIR *bodyLabel)
3695{
3696 /* Set up the place holder to reconstruct this Dalvik PC */
3697 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3698 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
3699 pcrLabel->operands[0] =
3700 (int) (cUnit->method->insns + entry->startOffset);
3701 pcrLabel->operands[1] = entry->startOffset;
3702 /* Insert the place holder to the growable list */
3703 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3704
3705 /*
3706 * Next, create two branches - one branch over to the loop body and the
3707 * other branch to the PCR cell to punt.
3708 */
3709 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3710 branchToBody->opCode = THUMB_B_UNCOND;
3711 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003712 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07003713 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3714
3715 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3716 branchToPCR->opCode = THUMB_B_UNCOND;
3717 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003718 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003719 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3720}
3721
Ben Chengba4fc8b2009-06-01 13:00:29 -07003722void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3723{
3724 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003725 ArmLIR *labelList =
3726 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003727 GrowableList chainingListByType[CHAINING_CELL_LAST];
3728 int i;
3729
3730 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003731 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003732 */
3733 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3734 dvmInitGrowableList(&chainingListByType[i], 2);
3735 }
3736
3737 BasicBlock **blockList = cUnit->blockList;
3738
Bill Buzbee6e963e12009-06-17 16:56:19 -07003739 if (cUnit->executionCount) {
3740 /*
3741 * Reserve 6 bytes at the beginning of the trace
3742 * +----------------------------+
3743 * | execution count (4 bytes) |
3744 * +----------------------------+
3745 * | chain cell offset (2 bytes)|
3746 * +----------------------------+
3747 * ...and then code to increment the execution
3748 * count:
3749 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3750 * sub r0, #10 @ back up to addr of executionCount
3751 * ldr r1, [r0]
3752 * add r1, #1
3753 * str r1, [r0]
3754 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003755 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3756 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003757 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003758 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003759 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003760 /* Thumb instruction used directly here to ensure correct size */
Ben Chengdcf3e5d2009-09-11 13:42:05 -07003761 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003762 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3763 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3764 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3765 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003766 } else {
3767 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003768 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003769 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003770 cUnit->headerSize = 2;
3771 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003772
Ben Chengba4fc8b2009-06-01 13:00:29 -07003773 /* Handle the content in each basic block */
3774 for (i = 0; i < cUnit->numBlocks; i++) {
3775 blockList[i]->visited = true;
3776 MIR *mir;
3777
3778 labelList[i].operands[0] = blockList[i]->startOffset;
3779
3780 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3781 /*
3782 * Append the label pseudo LIR first. Chaining cells will be handled
3783 * separately afterwards.
3784 */
3785 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3786 }
3787
Ben Cheng4238ec22009-08-24 16:32:22 -07003788 if (blockList[i]->blockType == ENTRY_BLOCK) {
3789 labelList[i].opCode = ARM_PSEUDO_ENTRY_BLOCK;
3790 if (blockList[i]->firstMIRInsn == NULL) {
3791 continue;
3792 } else {
3793 setupLoopEntryBlock(cUnit, blockList[i],
3794 &labelList[blockList[i]->fallThrough->id]);
3795 }
3796 } else if (blockList[i]->blockType == EXIT_BLOCK) {
3797 labelList[i].opCode = ARM_PSEUDO_EXIT_BLOCK;
3798 goto gen_fallthrough;
3799 } else if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003800 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003801 /* Reset the register state */
3802 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003803 } else {
3804 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003805 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003806 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003807 /* handle the codegen later */
3808 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003809 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003810 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003811 case CHAINING_CELL_INVOKE_SINGLETON:
3812 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003813 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003814 labelList[i].operands[0] =
3815 (int) blockList[i]->containingMethod;
3816 /* handle the codegen later */
3817 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003818 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3819 (void *) i);
3820 break;
3821 case CHAINING_CELL_INVOKE_PREDICTED:
3822 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003823 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003824 /* handle the codegen later */
3825 dvmInsertGrowableList(
3826 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3827 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003828 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003829 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003830 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003831 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003832 /* handle the codegen later */
3833 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003834 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003835 (void *) i);
3836 break;
3837 case PC_RECONSTRUCTION:
3838 /* Make sure exception handling block is next */
3839 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003840 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003841 assert (i == cUnit->numBlocks - 2);
3842 handlePCReconstruction(cUnit, &labelList[i+1]);
3843 break;
3844 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003845 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003846 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003847 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3848 jitToInterpEntries.dvmJitToInterpPunt),
3849 r1);
3850 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003851 }
3852 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003853#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003854 case CHAINING_CELL_BACKWARD_BRANCH:
3855 labelList[i].opCode =
3856 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3857 /* handle the codegen later */
3858 dvmInsertGrowableList(
3859 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3860 (void *) i);
3861 break;
3862#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003863 default:
3864 break;
3865 }
3866 continue;
3867 }
Ben Chenge9695e52009-06-16 16:11:47 -07003868
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003869 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003870
Ben Chengba4fc8b2009-06-01 13:00:29 -07003871 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003872 if (mir->dalvikInsn.opCode >= MIR_OP_FIRST) {
3873 handleExtendedMIR(cUnit, mir);
3874 continue;
3875 }
3876
Ben Chengba4fc8b2009-06-01 13:00:29 -07003877 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3878 InstructionFormat dalvikFormat =
3879 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003880 ArmLIR *boundaryLIR =
3881 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Cheng4238ec22009-08-24 16:32:22 -07003882 mir->offset, dalvikOpCode);
3883 if (mir->ssaRep) {
3884 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3885 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3886 }
3887
Ben Chenge9695e52009-06-16 16:11:47 -07003888 /* Remember the first LIR for this block */
3889 if (headLIR == NULL) {
3890 headLIR = boundaryLIR;
3891 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003892
Ben Chengba4fc8b2009-06-01 13:00:29 -07003893 bool notHandled;
3894 /*
3895 * Debugging: screen the opcode first to see if it is in the
3896 * do[-not]-compile list
3897 */
3898 bool singleStepMe =
3899 gDvmJit.includeSelectedOp !=
3900 ((gDvmJit.opList[dalvikOpCode >> 3] &
3901 (1 << (dalvikOpCode & 0x7))) !=
3902 0);
Jeff Hao97319a82009-08-12 16:57:15 -07003903#if defined(WITH_SELF_VERIFICATION)
3904 /* Punt on opcodes we can't replay */
3905 if (selfVerificationPuntOps(dalvikOpCode))
3906 singleStepMe = true;
3907#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003908 if (singleStepMe || cUnit->allSingleStep) {
3909 notHandled = false;
3910 genInterpSingleStep(cUnit, mir);
3911 } else {
3912 opcodeCoverage[dalvikOpCode]++;
3913 switch (dalvikFormat) {
3914 case kFmt10t:
3915 case kFmt20t:
3916 case kFmt30t:
3917 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3918 mir, blockList[i], labelList);
3919 break;
3920 case kFmt10x:
3921 notHandled = handleFmt10x(cUnit, mir);
3922 break;
3923 case kFmt11n:
3924 case kFmt31i:
3925 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3926 break;
3927 case kFmt11x:
3928 notHandled = handleFmt11x(cUnit, mir);
3929 break;
3930 case kFmt12x:
3931 notHandled = handleFmt12x(cUnit, mir);
3932 break;
3933 case kFmt20bc:
3934 notHandled = handleFmt20bc(cUnit, mir);
3935 break;
3936 case kFmt21c:
3937 case kFmt31c:
3938 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3939 break;
3940 case kFmt21h:
3941 notHandled = handleFmt21h(cUnit, mir);
3942 break;
3943 case kFmt21s:
3944 notHandled = handleFmt21s(cUnit, mir);
3945 break;
3946 case kFmt21t:
3947 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3948 labelList);
3949 break;
3950 case kFmt22b:
3951 case kFmt22s:
3952 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3953 break;
3954 case kFmt22c:
3955 notHandled = handleFmt22c(cUnit, mir);
3956 break;
3957 case kFmt22cs:
3958 notHandled = handleFmt22cs(cUnit, mir);
3959 break;
3960 case kFmt22t:
3961 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3962 labelList);
3963 break;
3964 case kFmt22x:
3965 case kFmt32x:
3966 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3967 break;
3968 case kFmt23x:
3969 notHandled = handleFmt23x(cUnit, mir);
3970 break;
3971 case kFmt31t:
3972 notHandled = handleFmt31t(cUnit, mir);
3973 break;
3974 case kFmt3rc:
3975 case kFmt35c:
3976 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3977 labelList);
3978 break;
3979 case kFmt3rms:
3980 case kFmt35ms:
3981 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3982 labelList);
3983 break;
3984 case kFmt3inline:
3985 notHandled = handleFmt3inline(cUnit, mir);
3986 break;
3987 case kFmt51l:
3988 notHandled = handleFmt51l(cUnit, mir);
3989 break;
3990 default:
3991 notHandled = true;
3992 break;
3993 }
3994 }
3995 if (notHandled) {
3996 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3997 mir->offset,
3998 dalvikOpCode, getOpcodeName(dalvikOpCode),
3999 dalvikFormat);
4000 dvmAbort();
4001 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004002 }
4003 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004004
4005 if (blockList[i]->blockType == ENTRY_BLOCK) {
4006 dvmCompilerAppendLIR(cUnit,
4007 (LIR *) cUnit->loopAnalysis->branchToBody);
4008 dvmCompilerAppendLIR(cUnit,
4009 (LIR *) cUnit->loopAnalysis->branchToPCR);
4010 }
4011
4012 if (headLIR) {
4013 /*
4014 * Eliminate redundant loads/stores and delay stores into later
4015 * slots
4016 */
4017 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4018 cUnit->lastLIRInsn);
4019 }
4020
4021gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004022 /*
4023 * Check if the block is terminated due to trace length constraint -
4024 * insert an unconditional branch to the chaining cell.
4025 */
4026 if (blockList[i]->needFallThroughBranch) {
4027 genUnconditionalBranch(cUnit,
4028 &labelList[blockList[i]->fallThrough->id]);
4029 }
4030
Ben Chengba4fc8b2009-06-01 13:00:29 -07004031 }
4032
Ben Chenge9695e52009-06-16 16:11:47 -07004033 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07004034 for (i = 0; i < CHAINING_CELL_LAST; i++) {
4035 size_t j;
4036 int *blockIdList = (int *) chainingListByType[i].elemList;
4037
4038 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4039
4040 /* No chaining cells of this type */
4041 if (cUnit->numChainingCells[i] == 0)
4042 continue;
4043
4044 /* Record the first LIR for a new type of chaining cell */
4045 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4046
4047 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4048 int blockId = blockIdList[j];
4049
4050 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004051 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004052
4053 /* Insert the pseudo chaining instruction */
4054 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4055
4056
4057 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07004058 case CHAINING_CELL_NORMAL:
4059 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004060 blockList[blockId]->startOffset);
4061 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004062 case CHAINING_CELL_INVOKE_SINGLETON:
4063 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004064 blockList[blockId]->containingMethod);
4065 break;
Ben Cheng38329f52009-07-07 14:19:20 -07004066 case CHAINING_CELL_INVOKE_PREDICTED:
4067 handleInvokePredictedChainingCell(cUnit);
4068 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07004069 case CHAINING_CELL_HOT:
4070 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004071 blockList[blockId]->startOffset);
4072 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004073#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07004074 case CHAINING_CELL_BACKWARD_BRANCH:
4075 handleBackwardBranchChainingCell(cUnit,
4076 blockList[blockId]->startOffset);
4077 break;
4078#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004079 default:
4080 dvmAbort();
4081 break;
4082 }
4083 }
4084 }
Ben Chenge9695e52009-06-16 16:11:47 -07004085
4086 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004087}
4088
4089/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004090bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004091{
Bill Buzbee716f1202009-07-23 13:22:09 -07004092 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004093
4094 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07004095 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004096 }
4097
4098 switch (work->kind) {
4099 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07004100 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004101 break;
4102 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004103 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07004104 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004105 break;
4106 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07004107 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004108 dvmAbort();
4109 }
4110 return res;
4111}
4112
Ben Chengba4fc8b2009-06-01 13:00:29 -07004113/* Architectural-specific debugging helpers go here */
4114void dvmCompilerArchDump(void)
4115{
4116 /* Print compiled opcode in this VM instance */
4117 int i, start, streak;
4118 char buf[1024];
4119
4120 streak = i = 0;
4121 buf[0] = 0;
4122 while (opcodeCoverage[i] == 0 && i < 256) {
4123 i++;
4124 }
4125 if (i == 256) {
4126 return;
4127 }
4128 for (start = i++, streak = 1; i < 256; i++) {
4129 if (opcodeCoverage[i]) {
4130 streak++;
4131 } else {
4132 if (streak == 1) {
4133 sprintf(buf+strlen(buf), "%x,", start);
4134 } else {
4135 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4136 }
4137 streak = 0;
4138 while (opcodeCoverage[i] == 0 && i < 256) {
4139 i++;
4140 }
4141 if (i < 256) {
4142 streak = 1;
4143 start = i;
4144 }
4145 }
4146 }
4147 if (streak) {
4148 if (streak == 1) {
4149 sprintf(buf+strlen(buf), "%x", start);
4150 } else {
4151 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4152 }
4153 }
4154 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004155 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004156 }
4157}