blob: 3c28c7b085b1246d6d6f7bcd3dbf99a95ff70d13 [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/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700486 * The following are building blocks to construct low-level IRs with 0 - 4
Ben Chengba4fc8b2009-06-01 13:00:29 -0700487 * operands.
488 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700489static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700490{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700491 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700492 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700493 insn->opCode = opCode;
494 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
495 return insn;
496}
497
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700498static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700499 int dest)
500{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700501 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700502 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700503 insn->opCode = opCode;
504 insn->operands[0] = dest;
505 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
506 return insn;
507}
508
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700509static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700510 int dest, int src1)
511{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700512 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700513 assert(isPseudoOpCode(opCode) ||
514 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700515 insn->opCode = opCode;
516 insn->operands[0] = dest;
517 insn->operands[1] = src1;
518 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
519 return insn;
520}
521
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700522static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700523 int dest, int src1, int src2)
524{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700525 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700526 assert(isPseudoOpCode(opCode) ||
527 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700528 insn->opCode = opCode;
529 insn->operands[0] = dest;
530 insn->operands[1] = src1;
531 insn->operands[2] = src2;
532 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
533 return insn;
534}
535
Bill Buzbee270c1d62009-08-13 16:58:07 -0700536static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
537 int dest, int src1, int src2, int info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700538{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700539 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
540 assert(isPseudoOpCode(opCode) ||
541 (EncodingMap[opCode].flags & IS_QUAD_OP));
542 insn->opCode = opCode;
543 insn->operands[0] = dest;
544 insn->operands[1] = src1;
545 insn->operands[2] = src2;
546 insn->operands[3] = info;
547 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
548 return insn;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700549}
550
Ben Chengba4fc8b2009-06-01 13:00:29 -0700551/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700552 * If the next instruction is a move-result or move-result-long,
553 * return the target Dalvik instruction and convert the next to a
554 * nop. Otherwise, return -1. Used to optimize method inlining.
555 */
556static int inlinedTarget(MIR *mir)
557{
558 if (mir->next &&
559 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
560 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT) ||
561 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE))) {
562 mir->next->dalvikInsn.opCode = OP_NOP;
563 return mir->next->dalvikInsn.vA;
564 } else {
565 return -1;
566 }
567}
568
569
570
571/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700572 * The following are building blocks to insert constants into the pool or
573 * instruction streams.
574 */
575
576/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700577static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700578{
579 /* Add the constant to the literal pool */
580 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700581 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700582 newValue->operands[0] = value;
583 newValue->generic.next = cUnit->wordList;
584 cUnit->wordList = (LIR *) newValue;
585 return newValue;
586 } else {
587 /* Add the constant in the middle of code stream */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700588 newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
589 newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700590 }
591 return NULL;
592}
593
594/*
595 * Search the existing constants in the literal pool for an exact or close match
596 * within specified delta (greater or equal to 0).
597 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700598static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700599 unsigned int delta)
600{
601 LIR *dataTarget = cUnit->wordList;
602 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700603 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700604 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700605 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700606 dataTarget = dataTarget->next;
607 }
608 return NULL;
609}
610
Ben Chengba4fc8b2009-06-01 13:00:29 -0700611/* Perform the actual operation for OP_RETURN_* */
612static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
613{
614 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
615#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700616 gDvmJit.returnOp++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700617#endif
618 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700619 /* Insert branch, but defer setting of target */
620 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700621 /* Set up the place holder to reconstruct this Dalvik PC */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700622 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
623 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700624 pcrLabel->operands[0] = dPC;
625 pcrLabel->operands[1] = mir->offset;
626 /* Insert the place holder to the growable list */
627 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
628 /* Branch to the PC reconstruction code */
629 branch->generic.target = (LIR *) pcrLabel;
630}
631
Ben Chengba4fc8b2009-06-01 13:00:29 -0700632/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700633static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
634 ArmLIR *branch,
635 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700636{
637 /* Set up the place holder to reconstruct this Dalvik PC */
638 if (pcrLabel == NULL) {
639 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700640 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
641 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700642 pcrLabel->operands[0] = dPC;
643 pcrLabel->operands[1] = dOffset;
644 /* Insert the place holder to the growable list */
645 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
646 }
647 /* Branch to the PC reconstruction code */
648 branch->generic.target = (LIR *) pcrLabel;
649 return pcrLabel;
650}
651
Ben Chengba4fc8b2009-06-01 13:00:29 -0700652
653/*
654 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
655 * satisfies.
656 */
Ben Cheng0fd31e42009-09-03 14:40:16 -0700657static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
658 ArmConditionCode cond,
659 int reg1, int reg2, int dOffset,
660 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700661{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700662 ArmLIR *res;
663 res = opRegReg(cUnit, OP_CMP, reg1, reg2);
664 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
665 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
666 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700667}
668
Ben Chenge9695e52009-06-16 16:11:47 -0700669/*
670 * Perform null-check on a register. vReg is the Dalvik register being checked,
671 * and mReg is the machine register holding the actual value. If internal state
672 * indicates that vReg has been checked before the check request is ignored.
673 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700674static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
675 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700676{
Ben Chenge9695e52009-06-16 16:11:47 -0700677 /* This particular Dalvik register has been null-checked */
678 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
679 return pcrLabel;
680 }
681 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
682 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
683}
684
685/*
686 * Perform zero-check on a register. Similar to genNullCheck but the value being
687 * checked does not have a corresponding Dalvik register.
688 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700689static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
690 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -0700691{
692 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700693}
694
695/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700696static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
697 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700698{
Ben Cheng0fd31e42009-09-03 14:40:16 -0700699 return genRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700700 pcrLabel);
701}
702
703/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700704static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
705 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700706{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700707 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700708 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
709}
710
711/* Load a wide field from an object instance */
712static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
713{
714 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700715 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700716
Ben Chenge9695e52009-06-16 16:11:47 -0700717 /* Allocate reg0..reg3 into physical registers r0..r3 */
718
719 /* See if vB is in a native register. If so, reuse it. */
720 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
721 /* Ping reg3 to the other register of the same pair containing reg2 */
722 reg3 = reg2 ^ 0x1;
723 /*
724 * Ping reg0 to the first register of the alternate register pair
725 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700726 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700727 reg1 = NEXT_REG(reg0);
728
729 loadValue(cUnit, dInsn->vB, reg2);
730 loadConstant(cUnit, reg3, fieldOffset);
731 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700732 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700733#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700734 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700735#else
736 int regMap = reg1 << 8 | reg0 << 4 | reg2;
737 selfVerificationMemOpWrapper(cUnit, regMap,
738 &selfVerificationLoadDoubleword);
Jeff Hao97319a82009-08-12 16:57:15 -0700739#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700740 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700741}
742
743/* Store a wide field to an object instance */
744static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
745{
746 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700747 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700748
Ben Chenge9695e52009-06-16 16:11:47 -0700749 /* Allocate reg0..reg3 into physical registers r0..r3 */
750
751 /* See if vB is in a native register. If so, reuse it. */
752 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
753 /* Ping reg3 to the other register of the same pair containing reg2 */
754 reg3 = reg2 ^ 0x1;
755 /*
756 * Ping reg0 to the first register of the alternate register pair
757 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700758 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700759 reg1 = NEXT_REG(reg0);
760
761
762 loadValue(cUnit, dInsn->vB, reg2);
763 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
764 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
765 loadConstant(cUnit, reg3, fieldOffset);
766 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700767 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700768#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700769 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700770#else
771 int regMap = reg1 << 8 | reg0 << 4 | reg2;
772 selfVerificationMemOpWrapper(cUnit, regMap,
773 &selfVerificationStoreDoubleword);
774#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700775}
776
777/*
778 * Load a field from an object instance
779 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700780 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700781static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700782 int fieldOffset)
783{
784 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700785 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700786
Ben Chenge9695e52009-06-16 16:11:47 -0700787 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
788 reg1 = NEXT_REG(reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700789 loadValue(cUnit, dInsn->vB, reg0);
Jeff Hao97319a82009-08-12 16:57:15 -0700790#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700791 loadBaseDisp(cUnit, mir, reg0, fieldOffset, reg1, size, true, dInsn->vB);
Jeff Hao97319a82009-08-12 16:57:15 -0700792#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700793 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700794 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700795 loadConstant(cUnit, reg1, fieldOffset);
796 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700797
Bill Buzbee270c1d62009-08-13 16:58:07 -0700798 int regMap = reg1 << 4 | reg0;
Jeff Hao97319a82009-08-12 16:57:15 -0700799 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
Jeff Hao97319a82009-08-12 16:57:15 -0700800#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700801 storeValue(cUnit, reg1, dInsn->vA, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700802}
803
804/*
805 * Store a field to an object instance
806 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700807 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700808static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700809 int fieldOffset)
810{
811 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700812 int reg0, reg1, reg2;
813
814 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
815 reg1 = NEXT_REG(reg0);
816 reg2 = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700817
Ben Chenge9695e52009-06-16 16:11:47 -0700818 loadValue(cUnit, dInsn->vB, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700819 loadValue(cUnit, dInsn->vA, reg2);
820 updateLiveRegister(cUnit, dInsn->vA, reg2);
821 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700822#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700823 storeBaseDisp(cUnit, reg0, fieldOffset, reg2, size, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700824#else
825 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700826 loadConstant(cUnit, reg1, fieldOffset);
827 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700828
829 int regMap = reg2 << 4 | reg0;
830 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
831
Bill Buzbee270c1d62009-08-13 16:58:07 -0700832 opRegReg(cUnit, OP_SUB, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700833#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700834}
835
836
Ben Chengba4fc8b2009-06-01 13:00:29 -0700837/*
838 * Generate array load
839 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700840 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700841static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700842 int vArray, int vIndex, int vDest, int scale)
843{
844 int lenOffset = offsetof(ArrayObject, length);
845 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700846 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847
Ben Chenge9695e52009-06-16 16:11:47 -0700848 reg0 = selectFirstRegister(cUnit, vArray, false);
849 reg1 = NEXT_REG(reg0);
850 reg2 = NEXT_REG(reg1);
851 reg3 = NEXT_REG(reg2);
852
853 loadValue(cUnit, vArray, reg2);
854 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700855
856 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -0700857 ArmLIR * pcrLabel = NULL;
858
859 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
860 pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
861 }
862
863 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
864 /* Get len */
865 loadWordDisp(cUnit, reg2, lenOffset, reg0);
866 /* reg2 -> array data */
867 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
868 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
869 } else {
870 /* reg2 -> array data */
871 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
872 }
Jeff Hao97319a82009-08-12 16:57:15 -0700873#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700874 if ((size == LONG) || (size == DOUBLE)) {
875 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
876 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
877 loadBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
878 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
879 loadBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
Ben Chenge9695e52009-06-16 16:11:47 -0700880 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700881 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700882 loadBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
Ben Chenge9695e52009-06-16 16:11:47 -0700883 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700884 }
Jeff Hao97319a82009-08-12 16:57:15 -0700885#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700886 //TODO: probably want to move this into loadBaseIndexed
887 void *funct = NULL;
888 switch(size) {
889 case LONG:
890 case DOUBLE:
Jeff Hao97319a82009-08-12 16:57:15 -0700891 funct = (void*) &selfVerificationLoadDoubleword;
892 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700893 case WORD:
Jeff Hao97319a82009-08-12 16:57:15 -0700894 funct = (void*) &selfVerificationLoad;
895 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700896 case UNSIGNED_HALF:
897 funct = (void*) &selfVerificationLoadHalfword;
898 break;
899 case SIGNED_HALF:
900 funct = (void*) &selfVerificationLoadSignedHalfword;
901 break;
902 case UNSIGNED_BYTE:
903 funct = (void*) &selfVerificationLoadByte;
904 break;
905 case SIGNED_BYTE:
906 funct = (void*) &selfVerificationLoadSignedByte;
907 break;
908 default:
909 assert(0);
910 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -0700911 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700912 /* Combine address and index */
913 if (scale)
914 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
915 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700916
917 int regMap = reg1 << 8 | reg0 << 4 | reg2;
918 selfVerificationMemOpWrapper(cUnit, regMap, funct);
919
Bill Buzbee270c1d62009-08-13 16:58:07 -0700920 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700921
Bill Buzbee270c1d62009-08-13 16:58:07 -0700922 if ((size == LONG) || (size == DOUBLE))
Jeff Hao97319a82009-08-12 16:57:15 -0700923 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
924 else
925 storeValue(cUnit, reg0, vDest, reg3);
926#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700927}
928
Ben Chengba4fc8b2009-06-01 13:00:29 -0700929/*
930 * Generate array store
931 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700932 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700933static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700934 int vArray, int vIndex, int vSrc, int scale)
935{
936 int lenOffset = offsetof(ArrayObject, length);
937 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700938 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700939
Ben Chenge9695e52009-06-16 16:11:47 -0700940 reg0 = selectFirstRegister(cUnit, vArray, false);
941 reg1 = NEXT_REG(reg0);
942 reg2 = NEXT_REG(reg1);
943 reg3 = NEXT_REG(reg2);
944
945 loadValue(cUnit, vArray, reg2);
946 loadValue(cUnit, vIndex, reg3);
947
Ben Cheng1efc9c52009-06-08 18:25:27 -0700948 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -0700949 ArmLIR * pcrLabel = NULL;
950
951 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
952 pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
953 }
954
955 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
956 /* Get len */
957 loadWordDisp(cUnit, reg2, lenOffset, reg0);
958 /* reg2 -> array data */
959 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
960 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
961 } else {
962 /* reg2 -> array data */
963 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone);
964 }
965
Ben Chenge9695e52009-06-16 16:11:47 -0700966 /* at this point, reg2 points to array, reg3 is unscaled index */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700967#if !defined(WITH_SELF_VERIFICATION)
968 if ((size == LONG) || (size == DOUBLE)) {
969 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
970 loadValuePair(cUnit, vSrc, reg0, reg1);
971 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
972 if (scale)
973 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
974 storeBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
975 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
976 storeBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
977 } else {
978 loadValue(cUnit, vSrc, reg0);
979 updateLiveRegister(cUnit, vSrc, reg0);
980 storeBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
981 }
982#else
983 //TODO: probably want to move this into storeBaseIndexed
984 void *funct = NULL;
985 switch(size) {
986 case LONG:
987 case DOUBLE:
988 funct = (void*) &selfVerificationStoreDoubleword;
989 break;
990 case WORD:
991 funct = (void*) &selfVerificationStore;
992 break;
993 case SIGNED_HALF:
994 case UNSIGNED_HALF:
995 funct = (void*) &selfVerificationStoreHalfword;
996 break;
997 case SIGNED_BYTE:
998 case UNSIGNED_BYTE:
999 funct = (void*) &selfVerificationStoreByte;
1000 break;
1001 default:
1002 assert(0);
1003 dvmAbort();
1004 }
1005
1006 /* Combine address and index */
1007 if ((size == LONG) || (size == DOUBLE)) {
Ben Chenge9695e52009-06-16 16:11:47 -07001008 loadValuePair(cUnit, vSrc, reg0, reg1);
1009 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001010 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001011 loadValue(cUnit, vSrc, reg0);
1012 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001013 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001014 if (scale)
1015 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
1016 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001017
1018 int regMap = reg1 << 8 | reg0 << 4 | reg2;
1019 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1020
Bill Buzbee270c1d62009-08-13 16:58:07 -07001021 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -07001022#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001023}
1024
1025static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1026 int vSrc1, int vShift)
1027{
Ben Chenge9695e52009-06-16 16:11:47 -07001028 /*
1029 * Don't mess with the regsiters here as there is a particular calling
1030 * convention to the out-of-line handler.
1031 */
1032 loadValue(cUnit, vShift, r2);
1033 loadValuePair(cUnit, vSrc1, r0, r1);
1034 switch( mir->dalvikInsn.opCode) {
1035 case OP_SHL_LONG:
1036 case OP_SHL_LONG_2ADDR:
1037 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1038 break;
1039 case OP_SHR_LONG:
1040 case OP_SHR_LONG_2ADDR:
1041 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1042 break;
1043 case OP_USHR_LONG:
1044 case OP_USHR_LONG_2ADDR:
1045 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1046 break;
1047 default:
1048 return true;
1049 }
1050 storeValuePair(cUnit, r0, r1, vDest, r2);
1051 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001052}
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001053bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1054 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001055{
Ben Chenge9695e52009-06-16 16:11:47 -07001056 /*
1057 * Don't optimize the regsiter usage here as they are governed by the EABI
1058 * calling convention.
1059 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001060 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001061 int reg0, reg1;
1062
Ben Chengba4fc8b2009-06-01 13:00:29 -07001063 /* TODO: use a proper include file to define these */
1064 float __aeabi_fadd(float a, float b);
1065 float __aeabi_fsub(float a, float b);
1066 float __aeabi_fdiv(float a, float b);
1067 float __aeabi_fmul(float a, float b);
1068 float fmodf(float a, float b);
1069
Ben Chenge9695e52009-06-16 16:11:47 -07001070 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1071 reg1 = NEXT_REG(reg0);
1072
Ben Chengba4fc8b2009-06-01 13:00:29 -07001073 switch (mir->dalvikInsn.opCode) {
1074 case OP_ADD_FLOAT_2ADDR:
1075 case OP_ADD_FLOAT:
1076 funct = (void*) __aeabi_fadd;
1077 break;
1078 case OP_SUB_FLOAT_2ADDR:
1079 case OP_SUB_FLOAT:
1080 funct = (void*) __aeabi_fsub;
1081 break;
1082 case OP_DIV_FLOAT_2ADDR:
1083 case OP_DIV_FLOAT:
1084 funct = (void*) __aeabi_fdiv;
1085 break;
1086 case OP_MUL_FLOAT_2ADDR:
1087 case OP_MUL_FLOAT:
1088 funct = (void*) __aeabi_fmul;
1089 break;
1090 case OP_REM_FLOAT_2ADDR:
1091 case OP_REM_FLOAT:
1092 funct = (void*) fmodf;
1093 break;
1094 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -07001095 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001096 opRegImm(cUnit, OP_ADD, reg0, 0x80000000, reg1);
Ben Chenge9695e52009-06-16 16:11:47 -07001097 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001098 return false;
1099 }
1100 default:
1101 return true;
1102 }
1103 loadConstant(cUnit, r2, (int)funct);
1104 loadValue(cUnit, vSrc1, r0);
1105 loadValue(cUnit, vSrc2, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001106 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001107 storeValue(cUnit, r0, vDest, r1);
1108 return false;
1109}
1110
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001111bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1112 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001113{
1114 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001115 int reg0, reg1, reg2;
1116
Ben Chengba4fc8b2009-06-01 13:00:29 -07001117 /* TODO: use a proper include file to define these */
1118 double __aeabi_dadd(double a, double b);
1119 double __aeabi_dsub(double a, double b);
1120 double __aeabi_ddiv(double a, double b);
1121 double __aeabi_dmul(double a, double b);
1122 double fmod(double a, double b);
1123
Ben Chenge9695e52009-06-16 16:11:47 -07001124 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1125 reg1 = NEXT_REG(reg0);
1126 reg2 = NEXT_REG(reg1);
1127
Ben Chengba4fc8b2009-06-01 13:00:29 -07001128 switch (mir->dalvikInsn.opCode) {
1129 case OP_ADD_DOUBLE_2ADDR:
1130 case OP_ADD_DOUBLE:
1131 funct = (void*) __aeabi_dadd;
1132 break;
1133 case OP_SUB_DOUBLE_2ADDR:
1134 case OP_SUB_DOUBLE:
1135 funct = (void*) __aeabi_dsub;
1136 break;
1137 case OP_DIV_DOUBLE_2ADDR:
1138 case OP_DIV_DOUBLE:
1139 funct = (void*) __aeabi_ddiv;
1140 break;
1141 case OP_MUL_DOUBLE_2ADDR:
1142 case OP_MUL_DOUBLE:
1143 funct = (void*) __aeabi_dmul;
1144 break;
1145 case OP_REM_DOUBLE_2ADDR:
1146 case OP_REM_DOUBLE:
1147 funct = (void*) fmod;
1148 break;
1149 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001150 loadValuePair(cUnit, vSrc2, reg0, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001151 opRegImm(cUnit, OP_ADD, reg1, 0x80000000, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001152 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153 return false;
1154 }
1155 default:
1156 return true;
1157 }
Ben Chenge9695e52009-06-16 16:11:47 -07001158 /*
1159 * Don't optimize the regsiter usage here as they are governed by the EABI
1160 * calling convention.
1161 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001162 loadConstant(cUnit, r4PC, (int)funct);
1163 loadValuePair(cUnit, vSrc1, r0, r1);
1164 loadValuePair(cUnit, vSrc2, r2, r3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001165 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001166 storeValuePair(cUnit, r0, r1, vDest, r2);
1167 return false;
1168}
1169
1170static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1171 int vSrc1, int vSrc2)
1172{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001173 OpKind firstOp = OP_BKPT;
1174 OpKind secondOp = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001175 bool callOut = false;
1176 void *callTgt;
1177 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -07001178 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001179 /* TODO - find proper .h file to declare these */
1180 long long __aeabi_ldivmod(long long op1, long long op2);
1181
1182 switch (mir->dalvikInsn.opCode) {
1183 case OP_NOT_LONG:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001184 firstOp = OP_MVN;
1185 secondOp = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001186 break;
1187 case OP_ADD_LONG:
1188 case OP_ADD_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001189 firstOp = OP_ADD;
1190 secondOp = OP_ADC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001191 break;
1192 case OP_SUB_LONG:
1193 case OP_SUB_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001194 firstOp = OP_SUB;
1195 secondOp = OP_SBC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001196 break;
1197 case OP_MUL_LONG:
1198 case OP_MUL_LONG_2ADDR:
1199 loadValuePair(cUnit, vSrc1, r0, r1);
1200 loadValuePair(cUnit, vSrc2, r2, r3);
1201 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
1202 storeValuePair(cUnit, r0, r1, vDest, r2);
1203 return false;
1204 break;
1205 case OP_DIV_LONG:
1206 case OP_DIV_LONG_2ADDR:
1207 callOut = true;
1208 retReg = r0;
1209 callTgt = (void*)__aeabi_ldivmod;
1210 break;
1211 /* NOTE - result is in r2/r3 instead of r0/r1 */
1212 case OP_REM_LONG:
1213 case OP_REM_LONG_2ADDR:
1214 callOut = true;
1215 callTgt = (void*)__aeabi_ldivmod;
1216 retReg = r2;
1217 break;
1218 case OP_AND_LONG:
1219 case OP_AND_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001220 firstOp = OP_AND;
1221 secondOp = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001222 break;
1223 case OP_OR_LONG:
1224 case OP_OR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001225 firstOp = OP_OR;
1226 secondOp = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001227 break;
1228 case OP_XOR_LONG:
1229 case OP_XOR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001230 firstOp = OP_XOR;
1231 secondOp = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001232 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001233 case OP_NEG_LONG: {
1234 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1235 reg1 = NEXT_REG(reg0);
1236 reg2 = NEXT_REG(reg1);
1237 reg3 = NEXT_REG(reg2);
1238
1239 loadValuePair(cUnit, vSrc2, reg0, reg1);
1240 loadConstant(cUnit, reg3, 0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001241 opRegRegReg(cUnit, OP_SUB, reg2, reg3, reg0);
1242 opRegReg(cUnit, OP_SBC, reg3, reg1);
Ben Cheng38329f52009-07-07 14:19:20 -07001243 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001244 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001245 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001246 default:
1247 LOGE("Invalid long arith op");
1248 dvmAbort();
1249 }
1250 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001251 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1252 reg1 = NEXT_REG(reg0);
1253 reg2 = NEXT_REG(reg1);
1254 reg3 = NEXT_REG(reg2);
1255
1256 loadValuePair(cUnit, vSrc1, reg0, reg1);
1257 loadValuePair(cUnit, vSrc2, reg2, reg3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001258 opRegReg(cUnit, firstOp, reg0, reg2);
1259 opRegReg(cUnit, secondOp, reg1, reg3);
1260 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001261 /*
Bill Buzbee270c1d62009-08-13 16:58:07 -07001262 * Don't optimize the register usage here as they are governed by the EABI
Ben Chenge9695e52009-06-16 16:11:47 -07001263 * calling convention.
1264 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001265 } else {
1266 loadValuePair(cUnit, vSrc2, r2, r3);
1267 loadConstant(cUnit, r4PC, (int) callTgt);
1268 loadValuePair(cUnit, vSrc1, r0, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001269 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001270 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1271 }
1272 return false;
1273}
1274
1275static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1276 int vSrc1, int vSrc2)
1277{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001278 OpKind op = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001279 bool callOut = false;
1280 bool checkZero = false;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001281 bool threeOperand = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001282 int retReg = r0;
1283 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -07001284 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001285
1286 /* TODO - find proper .h file to declare these */
1287 int __aeabi_idivmod(int op1, int op2);
1288 int __aeabi_idiv(int op1, int op2);
1289
1290 switch (mir->dalvikInsn.opCode) {
1291 case OP_NEG_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001292 op = OP_NEG;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001293 break;
1294 case OP_NOT_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001295 op = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001296 break;
1297 case OP_ADD_INT:
1298 case OP_ADD_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001299 op = OP_ADD;
1300 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001301 break;
1302 case OP_SUB_INT:
1303 case OP_SUB_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001304 op = OP_SUB;
1305 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001306 break;
1307 case OP_MUL_INT:
1308 case OP_MUL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001309 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001310 break;
1311 case OP_DIV_INT:
1312 case OP_DIV_INT_2ADDR:
1313 callOut = true;
1314 checkZero = true;
1315 callTgt = __aeabi_idiv;
1316 retReg = r0;
1317 break;
1318 /* NOTE: returns in r1 */
1319 case OP_REM_INT:
1320 case OP_REM_INT_2ADDR:
1321 callOut = true;
1322 checkZero = true;
1323 callTgt = __aeabi_idivmod;
1324 retReg = r1;
1325 break;
1326 case OP_AND_INT:
1327 case OP_AND_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001328 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001329 break;
1330 case OP_OR_INT:
1331 case OP_OR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001332 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001333 break;
1334 case OP_XOR_INT:
1335 case OP_XOR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001336 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001337 break;
1338 case OP_SHL_INT:
1339 case OP_SHL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001340 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001341 break;
1342 case OP_SHR_INT:
1343 case OP_SHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001344 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001345 break;
1346 case OP_USHR_INT:
1347 case OP_USHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001348 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001349 break;
1350 default:
1351 LOGE("Invalid word arith op: 0x%x(%d)",
1352 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1353 dvmAbort();
1354 }
1355 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001356 /* Try to allocate reg0 to the currently cached source operand */
1357 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1358 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1359 reg1 = NEXT_REG(reg0);
1360 regDest = NEXT_REG(reg1);
1361
1362 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1363 loadValue(cUnit, vSrc2, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001364 if (threeOperand) {
1365 opRegRegReg(cUnit, op, regDest, reg0, reg1);
1366 storeValue(cUnit, regDest, vDest, reg1);
1367 } else {
1368 opRegReg(cUnit, op, reg0, reg1);
1369 storeValue(cUnit, reg0, vDest, reg1);
1370 }
Ben Chenge9695e52009-06-16 16:11:47 -07001371 } else {
1372 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1373 reg1 = NEXT_REG(reg0);
1374 regDest = NEXT_REG(reg1);
1375
1376 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1377 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001378 if (threeOperand) {
1379 opRegRegReg(cUnit, op, regDest, reg1, reg0);
1380 storeValue(cUnit, regDest, vDest, reg1);
1381 } else {
1382 opRegReg(cUnit, op, reg1, reg0);
1383 storeValue(cUnit, reg1, vDest, reg0);
1384 }
Ben Chenge9695e52009-06-16 16:11:47 -07001385 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001386 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001387 /*
1388 * Load the callout target first since it will never be eliminated
1389 * and its value will be used first.
1390 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001391 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -07001392 /*
1393 * Load vSrc2 first if it is not cached in a native register or it
1394 * is in r0 which will be clobbered if vSrc1 is loaded first.
1395 */
1396 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1397 cUnit->registerScoreboard.nativeReg == r0) {
1398 /* Cannot be optimized and won't clobber r0 */
1399 loadValue(cUnit, vSrc2, r1);
1400 /* May be optimized if vSrc1 is cached */
1401 loadValue(cUnit, vSrc1, r0);
1402 } else {
1403 loadValue(cUnit, vSrc1, r0);
1404 loadValue(cUnit, vSrc2, r1);
1405 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001406 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -07001407 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001408 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001409 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001410 storeValue(cUnit, retReg, vDest, r2);
1411 }
1412 return false;
1413}
1414
1415static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1416{
1417 OpCode opCode = mir->dalvikInsn.opCode;
1418 int vA = mir->dalvikInsn.vA;
1419 int vB = mir->dalvikInsn.vB;
1420 int vC = mir->dalvikInsn.vC;
1421
1422 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1423 return genArithOpLong(cUnit,mir, vA, vA, vB);
1424 }
1425 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1426 return genArithOpLong(cUnit,mir, vA, vB, vC);
1427 }
1428 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1429 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1430 }
1431 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1432 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1433 }
1434 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1435 return genArithOpInt(cUnit,mir, vA, vA, vB);
1436 }
1437 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1438 return genArithOpInt(cUnit,mir, vA, vB, vC);
1439 }
1440 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001441 return genArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001442 }
1443 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001444 return genArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001445 }
1446 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001447 return genArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001448 }
1449 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001450 return genArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001451 }
1452 return true;
1453}
1454
Bill Buzbeed45ba372009-06-15 17:00:57 -07001455static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1456 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001457{
Ben Chenge9695e52009-06-16 16:11:47 -07001458 /*
1459 * Don't optimize the register usage since it calls out to template
1460 * functions
1461 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001462 loadConstant(cUnit, r2, (int)funct);
1463 if (srcSize == 1) {
1464 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1465 } else {
1466 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1467 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001468 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001469 if (tgtSize == 1) {
1470 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1471 } else {
1472 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1473 }
1474 return false;
1475}
1476
Ben Chengba4fc8b2009-06-01 13:00:29 -07001477static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1478 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001479 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001480{
1481 unsigned int i;
1482 unsigned int regMask = 0;
1483
1484 /* Load arguments to r0..r4 */
1485 for (i = 0; i < dInsn->vA; i++) {
1486 regMask |= 1 << i;
1487 loadValue(cUnit, dInsn->arg[i], i);
1488 }
1489 if (regMask) {
1490 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001491 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1492 sizeof(StackSaveArea) + (dInsn->vA << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001493 /* generate null check */
1494 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001495 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1496 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001497 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001498 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001499 }
1500}
1501
1502static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1503 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001504 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001505{
1506 int srcOffset = dInsn->vC << 2;
1507 int numArgs = dInsn->vA;
1508 int regMask;
1509 /*
1510 * r4PC : &rFP[vC]
1511 * r7: &newFP[0]
1512 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001513 opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001514 /* load [r0 .. min(numArgs,4)] */
1515 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001516 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001517
Bill Buzbee270c1d62009-08-13 16:58:07 -07001518 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1519 sizeof(StackSaveArea) + (numArgs << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001520 /* generate null check */
1521 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001522 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001523 }
1524
1525 /*
1526 * Handle remaining 4n arguments:
1527 * store previously loaded 4 values and load the next 4 values
1528 */
1529 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001530 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001531 /*
1532 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001533 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001534 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001535 opImm(cUnit, OP_PUSH, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001536 /* No need to generate the loop structure if numArgs <= 11 */
1537 if (numArgs > 11) {
1538 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001539 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001540 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001541 storeMultiple(cUnit, r7, regMask);
1542 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001543 /* No need to generate the loop structure if numArgs <= 11 */
1544 if (numArgs > 11) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001545 opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001546 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1547 }
1548 }
1549
1550 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001551 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001552
1553 /* Generate the loop epilogue - don't use r0 */
1554 if ((numArgs > 4) && (numArgs % 4)) {
1555 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001556 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001557 }
1558 if (numArgs >= 8)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001559 opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001560
1561 /* Save the modulo 4 arguments */
1562 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001563 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001564 }
1565}
1566
Ben Cheng38329f52009-07-07 14:19:20 -07001567/*
1568 * Generate code to setup the call stack then jump to the chaining cell if it
1569 * is not a native method.
1570 */
1571static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001572 BasicBlock *bb, ArmLIR *labelList,
1573 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001574 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001575{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001576 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001577
1578 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001579 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001580 /* r4PC = dalvikCallsite */
1581 loadConstant(cUnit, r4PC,
1582 (int) (cUnit->method->insns + mir->offset));
1583 addrRetChain->generic.target = (LIR *) retChainingCell;
1584 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001585 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001586 * r1 = &ChainingCell
1587 * r4PC = callsiteDPC
1588 */
1589 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001590 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001591#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001592 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001593#endif
1594 } else {
1595 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1596#if defined(INVOKE_STATS)
1597 gDvmJit.invokeChain++;
1598#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001599 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001600 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1601 }
1602 /* Handle exceptions using the interpreter */
1603 genTrap(cUnit, mir->offset, pcrLabel);
1604}
1605
Ben Cheng38329f52009-07-07 14:19:20 -07001606/*
1607 * Generate code to check the validity of a predicted chain and take actions
1608 * based on the result.
1609 *
1610 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1611 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1612 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1613 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1614 * 0x426a99b2 : blx_2 see above --+
1615 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1616 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1617 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1618 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1619 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1620 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1621 * 0x426a99c0 : blx r7 --+
1622 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1623 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1624 * 0x426a99c6 : blx_2 see above --+
1625 */
1626static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1627 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001628 ArmLIR *retChainingCell,
1629 ArmLIR *predChainingCell,
1630 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001631{
1632 /* "this" is already left in r0 by genProcessArgs* */
1633
1634 /* r4PC = dalvikCallsite */
1635 loadConstant(cUnit, r4PC,
1636 (int) (cUnit->method->insns + mir->offset));
1637
1638 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001639 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001640 addrRetChain->generic.target = (LIR *) retChainingCell;
1641
1642 /* r2 = &predictedChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001643 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, OP_ADD, r2, rpc, 0,
1644 rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001645 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1646
1647 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1648
1649 /* return through lr - jump to the chaining cell */
1650 genUnconditionalBranch(cUnit, predChainingCell);
1651
1652 /*
1653 * null-check on "this" may have been eliminated, but we still need a PC-
1654 * reconstruction label for stack overflow bailout.
1655 */
1656 if (pcrLabel == NULL) {
1657 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001658 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1659 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001660 pcrLabel->operands[0] = dPC;
1661 pcrLabel->operands[1] = mir->offset;
1662 /* Insert the place holder to the growable list */
1663 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1664 }
1665
1666 /* return through lr+2 - punt to the interpreter */
1667 genUnconditionalBranch(cUnit, pcrLabel);
1668
1669 /*
1670 * return through lr+4 - fully resolve the callee method.
1671 * r1 <- count
1672 * r2 <- &predictedChainCell
1673 * r3 <- this->class
1674 * r4 <- dPC
1675 * r7 <- this->class->vtable
1676 */
1677
1678 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001679 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001680
1681 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001682 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001683
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001684 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001685 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001686
Bill Buzbee270c1d62009-08-13 16:58:07 -07001687 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1688 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001689
1690 /*
1691 * r0 = calleeMethod
1692 * r2 = &predictedChainingCell
1693 * r3 = class
1694 *
1695 * &returnChainingCell has been loaded into r1 but is not needed
1696 * when patching the chaining cell and will be clobbered upon
1697 * returning so it will be reconstructed again.
1698 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001699 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001700
1701 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001702 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001703 addrRetChain->generic.target = (LIR *) retChainingCell;
1704
1705 bypassRechaining->generic.target = (LIR *) addrRetChain;
1706 /*
1707 * r0 = calleeMethod,
1708 * r1 = &ChainingCell,
1709 * r4PC = callsiteDPC,
1710 */
1711 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1712#if defined(INVOKE_STATS)
1713 gDvmJit.invokePredictedChain++;
1714#endif
1715 /* Handle exceptions using the interpreter */
1716 genTrap(cUnit, mir->offset, pcrLabel);
1717}
1718
1719/*
1720 * Up calling this function, "this" is stored in r0. The actual class will be
1721 * chased down off r0 and the predicted one will be retrieved through
1722 * predictedChainingCell then a comparison is performed to see whether the
1723 * previously established chaining is still valid.
1724 *
1725 * The return LIR is a branch based on the comparison result. The actual branch
1726 * target will be setup in the caller.
1727 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001728static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1729 ArmLIR *predChainingCell,
1730 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001731 MIR *mir)
1732{
1733 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001734 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001735
1736 /*
1737 * r2 now contains predicted class. The starting offset of the
1738 * cached value is 4 bytes into the chaining cell.
1739 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001740 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001741 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07001742 getPredictedClass->generic.target = (LIR *) predChainingCell;
1743
1744 /*
1745 * r0 now contains predicted method. The starting offset of the
1746 * cached value is 8 bytes into the chaining cell.
1747 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001748 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001749 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001750 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1751
1752 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001753 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001754 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001755 getRechainingRequestCount->generic.target =
1756 (LIR *) predChainingCell;
1757
1758 /* r4PC = dalvikCallsite */
1759 loadConstant(cUnit, r4PC,
1760 (int) (cUnit->method->insns + mir->offset));
1761
1762 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001763 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001764 addrRetChain->generic.target = (LIR *) retChainingCell;
1765
1766 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001767 opRegReg(cUnit, OP_CMP, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001768
Bill Buzbee270c1d62009-08-13 16:58:07 -07001769 return opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001770}
1771
Ben Chengba4fc8b2009-06-01 13:00:29 -07001772/* Geneate a branch to go back to the interpreter */
1773static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1774{
1775 /* r0 = dalvik pc */
1776 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001777 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1778 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1779 jitToInterpEntries.dvmJitToInterpPunt), r1);
1780 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001781}
1782
1783/*
1784 * Attempt to single step one instruction using the interpreter and return
1785 * to the compiled code for the next Dalvik instruction
1786 */
1787static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1788{
1789 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1790 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1791 kInstrCanThrow;
1792 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1793 genPuntToInterp(cUnit, mir->offset);
1794 return;
1795 }
1796 int entryAddr = offsetof(InterpState,
1797 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001798 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001799 /* r0 = dalvik pc */
1800 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1801 /* r1 = dalvik pc of following instruction */
1802 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001803 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001804}
1805
Bill Buzbee270c1d62009-08-13 16:58:07 -07001806/* Generate conditional branch instructions */
1807static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1808 ArmConditionCode cond,
1809 ArmLIR *target)
1810{
1811 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
1812 branch->generic.target = (LIR *) target;
1813 return branch;
1814}
Ben Chengba4fc8b2009-06-01 13:00:29 -07001815
Bill Buzbee270c1d62009-08-13 16:58:07 -07001816/* Generate unconditional branch instructions */
1817static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1818{
1819 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
1820 branch->generic.target = (LIR *) target;
1821 return branch;
1822}
1823
1824/* Load the address of a Dalvik register on the frame */
1825static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
1826{
1827 return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
1828}
1829
1830/* Load a single value from rFP[src] and store them into rDest */
1831static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
1832{
1833 return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
1834}
1835
1836/* Load a word at base + displacement. Displacement must be word multiple */
1837static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
1838 int rDest)
1839{
1840 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
1841 -1);
1842}
1843
1844static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
1845 int displacement, int rSrc, int rScratch)
1846{
1847 return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
1848}
1849
1850/* Store a value from rSrc to vDest */
1851static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
1852 int rScratch)
1853{
1854 killNullCheckedRegister(cUnit, vDest);
1855 updateLiveRegister(cUnit, vDest, rSrc);
1856 return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
1857}
1858/*
1859 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
1860 * rDestHi
1861 */
1862static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
1863 int rDestHi)
1864{
1865 ArmLIR *res;
1866 /* Use reg + imm5*4 to load the values if possible */
1867 if (vSrc <= 30) {
1868 res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
1869 loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
1870 } else {
1871 assert(rDestLo < rDestHi);
1872 res = loadValueAddress(cUnit, vSrc, rDestLo);
1873 loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
1874 }
1875 return res;
1876}
1877
1878/*
1879 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
1880 * vDest+1
1881 */
1882static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
1883 int vDest, int rScratch)
1884{
1885 ArmLIR *res;
1886 killNullCheckedRegister(cUnit, vDest);
1887 killNullCheckedRegister(cUnit, vDest+1);
1888 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
1889
1890 /* Use reg + imm5*4 to store the values if possible */
1891 if (vDest <= 30) {
1892 res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
1893 storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
1894 } else {
1895 assert(rSrcLo < rSrcHi);
1896 res = loadValueAddress(cUnit, vDest, rScratch);
1897 storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
1898 }
1899 return res;
1900}
1901
1902static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1903{
1904 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
1905 dvmCompilerAppendLIR(cUnit, (LIR*)res);
1906 return res;
1907}
1908
Ben Chengba4fc8b2009-06-01 13:00:29 -07001909/*
1910 * The following are the first-level codegen routines that analyze the format
1911 * of each bytecode then either dispatch special purpose codegen routines
1912 * or produce corresponding Thumb instructions directly.
1913 */
1914
1915static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001916 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001917{
1918 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1919 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1920 return false;
1921}
1922
1923static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1924{
1925 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1926 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1927 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1928 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1929 return true;
1930 }
1931 switch (dalvikOpCode) {
1932 case OP_RETURN_VOID:
1933 genReturnCommon(cUnit,mir);
1934 break;
1935 case OP_UNUSED_73:
1936 case OP_UNUSED_79:
1937 case OP_UNUSED_7A:
1938 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1939 return true;
1940 case OP_NOP:
1941 break;
1942 default:
1943 return true;
1944 }
1945 return false;
1946}
1947
1948static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1949{
Ben Chenge9695e52009-06-16 16:11:47 -07001950 int reg0, reg1, reg2;
1951
Ben Chengba4fc8b2009-06-01 13:00:29 -07001952 switch (mir->dalvikInsn.opCode) {
1953 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001954 case OP_CONST_4: {
1955 /* Avoid using the previously used register */
1956 reg0 = selectFirstRegister(cUnit, vNone, false);
1957 reg1 = NEXT_REG(reg0);
1958 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1959 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001960 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001961 }
1962 case OP_CONST_WIDE_32: {
1963 /* Avoid using the previously used register */
1964 reg0 = selectFirstRegister(cUnit, vNone, true);
1965 reg1 = NEXT_REG(reg0);
1966 reg2 = NEXT_REG(reg1);
1967 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001968 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07001969 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001970 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001971 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001972 default:
1973 return true;
1974 }
1975 return false;
1976}
1977
1978static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1979{
Ben Chenge9695e52009-06-16 16:11:47 -07001980 int reg0, reg1, reg2;
1981
1982 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001983 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001984 case OP_CONST_HIGH16: {
1985 reg0 = selectFirstRegister(cUnit, vNone, false);
1986 reg1 = NEXT_REG(reg0);
1987 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1988 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001989 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001990 }
1991 case OP_CONST_WIDE_HIGH16: {
1992 reg0 = selectFirstRegister(cUnit, vNone, true);
1993 reg1 = NEXT_REG(reg0);
1994 reg2 = NEXT_REG(reg1);
1995 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1996 loadConstant(cUnit, reg0, 0);
1997 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001998 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001999 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002000 default:
2001 return true;
2002 }
2003 return false;
2004}
2005
2006static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2007{
2008 /* For OP_THROW_VERIFICATION_ERROR */
2009 genInterpSingleStep(cUnit, mir);
2010 return false;
2011}
2012
2013static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2014{
Ben Chenge9695e52009-06-16 16:11:47 -07002015 /* Native register to use if the interested value is vA */
2016 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2017 /* Native register to use if source is not from Dalvik registers */
2018 int regvNone = selectFirstRegister(cUnit, vNone, false);
2019 /* Similar to regvA but for 64-bit values */
2020 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
2021 /* Similar to regvNone but for 64-bit values */
2022 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
2023
Ben Chengba4fc8b2009-06-01 13:00:29 -07002024 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002025 case OP_CONST_STRING_JUMBO:
2026 case OP_CONST_STRING: {
2027 void *strPtr = (void*)
2028 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2029 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002030 loadConstant(cUnit, regvNone, (int) strPtr );
2031 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002032 break;
2033 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002034 case OP_CONST_CLASS: {
2035 void *classPtr = (void*)
2036 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2037 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002038 loadConstant(cUnit, regvNone, (int) classPtr );
2039 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002040 break;
2041 }
2042 case OP_SGET_OBJECT:
2043 case OP_SGET_BOOLEAN:
2044 case OP_SGET_CHAR:
2045 case OP_SGET_BYTE:
2046 case OP_SGET_SHORT:
2047 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002048 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002049 void *fieldPtr = (void*)
2050 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2051 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002052 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002053#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002054 loadWordDisp(cUnit, regvNone, 0, regvNone);
Jeff Hao97319a82009-08-12 16:57:15 -07002055#else
2056 int regMap = regvNone << 4 | regvNone;
2057 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2058
Jeff Hao97319a82009-08-12 16:57:15 -07002059#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002060 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002061 break;
2062 }
2063 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002064 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002065 void *fieldPtr = (void*)
2066 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002067 int reg0, reg1, reg2;
2068
Ben Chengba4fc8b2009-06-01 13:00:29 -07002069 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002070 reg0 = regvNoneWide;
2071 reg1 = NEXT_REG(reg0);
2072 reg2 = NEXT_REG(reg1);
2073 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002074#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002075 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002076#else
2077 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2078 selfVerificationMemOpWrapper(cUnit, regMap,
2079 &selfVerificationLoadDoubleword);
2080
Jeff Hao97319a82009-08-12 16:57:15 -07002081#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002082 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002083 break;
2084 }
2085 case OP_SPUT_OBJECT:
2086 case OP_SPUT_BOOLEAN:
2087 case OP_SPUT_CHAR:
2088 case OP_SPUT_BYTE:
2089 case OP_SPUT_SHORT:
2090 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002091 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002092 void *fieldPtr = (void*)
2093 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002094
Ben Chengba4fc8b2009-06-01 13:00:29 -07002095 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002096 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
2097 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
2098 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002099#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002100 storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
Jeff Hao97319a82009-08-12 16:57:15 -07002101#else
2102 int regMap = regvA << 4 | NEXT_REG(regvA);
2103 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2104#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002105 break;
2106 }
2107 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002108 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002109 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002110 void *fieldPtr = (void*)
2111 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002112
Ben Chengba4fc8b2009-06-01 13:00:29 -07002113 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002114 reg0 = regvAWide;
2115 reg1 = NEXT_REG(reg0);
2116 reg2 = NEXT_REG(reg1);
2117 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2118 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2119 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002120#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002121 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002122#else
2123 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2124 selfVerificationMemOpWrapper(cUnit, regMap,
2125 &selfVerificationStoreDoubleword);
2126#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002127 break;
2128 }
2129 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002130 /*
2131 * Obey the calling convention and don't mess with the register
2132 * usage.
2133 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002134 ClassObject *classPtr = (void*)
2135 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2136 assert(classPtr != NULL);
2137 assert(classPtr->status & CLASS_INITIALIZED);
2138 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
2139 /* It's going to throw, just let the interp. deal with it. */
2140 genInterpSingleStep(cUnit, mir);
2141 return false;
2142 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002143 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002144 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002145 genExportPC(cUnit, mir, r2, r3 );
2146 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002147 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002148 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002149 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2150 break;
2151 }
2152 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002153 /*
2154 * Obey the calling convention and don't mess with the register
2155 * usage.
2156 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002157 ClassObject *classPtr =
2158 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2159 loadConstant(cUnit, r1, (int) classPtr );
2160 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002161 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* Null? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002162 ArmLIR *branch1 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002163 opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002164 /* r0 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002165 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002166 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002167 opRegReg(cUnit, OP_CMP, r0, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002168 ArmLIR *branch2 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002169 opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2170 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002171 /* check cast failed - punt to the interpreter */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002172 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002173 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002174 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002175 branch1->generic.target = (LIR *)target;
2176 branch2->generic.target = (LIR *)target;
2177 break;
2178 }
2179 default:
2180 return true;
2181 }
2182 return false;
2183}
2184
2185static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2186{
2187 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2188 switch (dalvikOpCode) {
2189 case OP_MOVE_EXCEPTION: {
2190 int offset = offsetof(InterpState, self);
2191 int exOffset = offsetof(Thread, exception);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002192 loadWordDisp(cUnit, rGLUE, offset, r1);
2193 loadWordDisp(cUnit, r1, exOffset, r0);
Ben Chenge9695e52009-06-16 16:11:47 -07002194 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002195 break;
2196 }
2197 case OP_MOVE_RESULT:
2198 case OP_MOVE_RESULT_OBJECT: {
2199 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002200 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002201 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2202 break;
2203 }
2204 case OP_MOVE_RESULT_WIDE: {
2205 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002206 loadWordDisp(cUnit, rGLUE, offset, r0);
2207 loadWordDisp(cUnit, rGLUE, offset+4, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002208 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2209 break;
2210 }
2211 case OP_RETURN_WIDE: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002212 int vSrc = mir->dalvikInsn.vA;
2213 int reg0 = selectFirstRegister(cUnit, vSrc, true);
2214 int reg1 = NEXT_REG(reg0);
2215 int rScratch = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002216 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002217 loadValuePair(cUnit, vSrc, reg0, reg1);
2218 storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
2219 storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002220 genReturnCommon(cUnit,mir);
2221 break;
2222 }
2223 case OP_RETURN:
2224 case OP_RETURN_OBJECT: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002225 int vSrc = mir->dalvikInsn.vA;
2226 int reg0 = selectFirstRegister(cUnit, vSrc, false);
2227 int rScratch = NEXT_REG(reg0);
2228 loadValue(cUnit, vSrc, reg0);
2229 storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
2230 reg0, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002231 genReturnCommon(cUnit,mir);
2232 break;
2233 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002234 case OP_MONITOR_ENTER:
2235 case OP_MONITOR_EXIT: {
2236 int offset = offsetof(InterpState, self);
2237 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002238 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002239 if (dalvikOpCode == OP_MONITOR_ENTER) {
2240 loadConstant(cUnit, r2, (int)dvmLockObject);
2241 } else {
2242 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2243 }
Ben Chenge9695e52009-06-16 16:11:47 -07002244 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002245 /* Do the call */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002246 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002247 break;
2248 }
2249 case OP_THROW: {
2250 genInterpSingleStep(cUnit, mir);
2251 break;
2252 }
2253 default:
2254 return true;
2255 }
2256 return false;
2257}
2258
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002259static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002260{
2261 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002262
Ben Chengba4fc8b2009-06-01 13:00:29 -07002263 float __aeabi_i2f( int op1 );
2264 int __aeabi_f2iz( float op1 );
2265 float __aeabi_d2f( double op1 );
2266 double __aeabi_f2d( float op1 );
2267 double __aeabi_i2d( int op1 );
2268 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002269 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002270 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002271 s8 dvmJitf2l( float op1 );
2272 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002273
Bill Buzbeed45ba372009-06-15 17:00:57 -07002274 switch (opCode) {
2275 case OP_INT_TO_FLOAT:
2276 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2277 case OP_FLOAT_TO_INT:
2278 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2279 case OP_DOUBLE_TO_FLOAT:
2280 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2281 case OP_FLOAT_TO_DOUBLE:
2282 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2283 case OP_INT_TO_DOUBLE:
2284 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2285 case OP_DOUBLE_TO_INT:
2286 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2287 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002288 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002289 case OP_LONG_TO_FLOAT:
2290 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2291 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002292 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002293 case OP_LONG_TO_DOUBLE:
2294 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2295 default:
2296 return true;
2297 }
2298 return false;
2299}
2300
2301static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2302{
2303 OpCode opCode = mir->dalvikInsn.opCode;
2304 int vSrc1Dest = mir->dalvikInsn.vA;
2305 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002306 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002307
Ben Chengba4fc8b2009-06-01 13:00:29 -07002308 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2309 return genArithOp( cUnit, mir );
2310 }
2311
Ben Chenge9695e52009-06-16 16:11:47 -07002312 /*
2313 * If data type is 64-bit, re-calculate the register numbers in the
2314 * corresponding cases.
2315 */
2316 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2317 reg1 = NEXT_REG(reg0);
2318 reg2 = NEXT_REG(reg1);
2319
Ben Chengba4fc8b2009-06-01 13:00:29 -07002320 switch (opCode) {
2321 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002322 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002323 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002324 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002325 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002326 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002327 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002328 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002329 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002330 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002331 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002332 case OP_NEG_INT:
2333 case OP_NOT_INT:
2334 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2335 case OP_NEG_LONG:
2336 case OP_NOT_LONG:
2337 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2338 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002339 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002340 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002341 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07002342 case OP_MOVE_WIDE: {
2343 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2344 reg1 = NEXT_REG(reg0);
2345 reg2 = NEXT_REG(reg1);
2346
2347 loadValuePair(cUnit, vSrc2, reg0, reg1);
2348 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002349 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002350 }
2351 case OP_INT_TO_LONG: {
2352 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2353 reg1 = NEXT_REG(reg0);
2354 reg2 = NEXT_REG(reg1);
2355
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002356 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002357 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002358 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002359 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002360 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002361 case OP_MOVE:
2362 case OP_MOVE_OBJECT:
2363 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002364 loadValue(cUnit, vSrc2, reg0);
2365 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002366 break;
2367 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07002368 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002369 opRegReg(cUnit, OP_2BYTE, reg1, reg0);
2370 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002371 break;
2372 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07002373 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002374 opRegReg(cUnit, OP_2SHORT, reg1, reg0);
2375 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002376 break;
2377 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07002378 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002379 opRegReg(cUnit, OP_2CHAR, reg1, reg0);
2380 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002381 break;
2382 case OP_ARRAY_LENGTH: {
2383 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002384 loadValue(cUnit, vSrc2, reg1);
2385 genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
2386 loadWordDisp(cUnit, reg1, lenOffset, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -07002387 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002388 break;
2389 }
2390 default:
2391 return true;
2392 }
2393 return false;
2394}
2395
2396static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2397{
2398 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07002399 int reg0, reg1, reg2;
2400
Ben Chengba4fc8b2009-06-01 13:00:29 -07002401 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2402 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002403 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002404 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002405
2406 reg0 = selectFirstRegister(cUnit, vNone, true);
2407 reg1 = NEXT_REG(reg0);
2408 reg2 = NEXT_REG(reg1);
2409
2410 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002411 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002412
2413 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07002414 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002415 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002416 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002417 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002418
Ben Chenge9695e52009-06-16 16:11:47 -07002419 reg0 = selectFirstRegister(cUnit, vNone, false);
2420 reg1 = NEXT_REG(reg0);
2421
2422 loadConstant(cUnit, reg0, BBBB);
2423 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002424 } else {
2425 return true;
2426 }
2427 return false;
2428}
2429
2430/* Compare agaist zero */
2431static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002432 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002433{
2434 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002435 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002436 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002437
Ben Chenge9695e52009-06-16 16:11:47 -07002438 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002439 opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002440
Bill Buzbee270c1d62009-08-13 16:58:07 -07002441//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002442 switch (dalvikOpCode) {
2443 case OP_IF_EQZ:
2444 cond = ARM_COND_EQ;
2445 break;
2446 case OP_IF_NEZ:
2447 cond = ARM_COND_NE;
2448 break;
2449 case OP_IF_LTZ:
2450 cond = ARM_COND_LT;
2451 break;
2452 case OP_IF_GEZ:
2453 cond = ARM_COND_GE;
2454 break;
2455 case OP_IF_GTZ:
2456 cond = ARM_COND_GT;
2457 break;
2458 case OP_IF_LEZ:
2459 cond = ARM_COND_LE;
2460 break;
2461 default:
2462 cond = 0;
2463 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2464 dvmAbort();
2465 }
2466 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2467 /* This mostly likely will be optimized away in a later phase */
2468 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2469 return false;
2470}
2471
2472static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2473{
2474 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2475 int vSrc = mir->dalvikInsn.vB;
2476 int vDest = mir->dalvikInsn.vA;
2477 int lit = mir->dalvikInsn.vC;
Bill Buzbee270c1d62009-08-13 16:58:07 -07002478 OpKind op;
Ben Chenge9695e52009-06-16 16:11:47 -07002479 int reg0, reg1, regDest;
2480
2481 reg0 = selectFirstRegister(cUnit, vSrc, false);
2482 reg1 = NEXT_REG(reg0);
2483 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002484
Ben Chengba4fc8b2009-06-01 13:00:29 -07002485 int __aeabi_idivmod(int op1, int op2);
2486 int __aeabi_idiv(int op1, int op2);
2487
2488 switch (dalvikOpCode) {
2489 case OP_ADD_INT_LIT8:
2490 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002491 loadValue(cUnit, vSrc, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002492 opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
2493 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002494 break;
2495
2496 case OP_RSUB_INT_LIT8:
2497 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002498 loadValue(cUnit, vSrc, reg1);
2499 loadConstant(cUnit, reg0, lit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002500 opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
2501 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002502 break;
2503
2504 case OP_MUL_INT_LIT8:
2505 case OP_MUL_INT_LIT16:
2506 case OP_AND_INT_LIT8:
2507 case OP_AND_INT_LIT16:
2508 case OP_OR_INT_LIT8:
2509 case OP_OR_INT_LIT16:
2510 case OP_XOR_INT_LIT8:
2511 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002512 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002513 switch (dalvikOpCode) {
2514 case OP_MUL_INT_LIT8:
2515 case OP_MUL_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002516 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002517 break;
2518 case OP_AND_INT_LIT8:
2519 case OP_AND_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002520 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002521 break;
2522 case OP_OR_INT_LIT8:
2523 case OP_OR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002524 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002525 break;
2526 case OP_XOR_INT_LIT8:
2527 case OP_XOR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002528 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002529 break;
2530 default:
2531 dvmAbort();
2532 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002533 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2534 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002535 break;
2536
2537 case OP_SHL_INT_LIT8:
2538 case OP_SHR_INT_LIT8:
2539 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002540 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002541 switch (dalvikOpCode) {
2542 case OP_SHL_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002543 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002544 break;
2545 case OP_SHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002546 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002547 break;
2548 case OP_USHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002549 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002550 break;
2551 default: dvmAbort();
2552 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002553 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2554 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002555 break;
2556
2557 case OP_DIV_INT_LIT8:
2558 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002559 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002560 if (lit == 0) {
2561 /* Let the interpreter deal with div by 0 */
2562 genInterpSingleStep(cUnit, mir);
2563 return false;
2564 }
2565 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2566 loadConstant(cUnit, r1, lit);
2567 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002568 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002569 storeValue(cUnit, r0, vDest, r2);
2570 break;
2571
2572 case OP_REM_INT_LIT8:
2573 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002574 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002575 if (lit == 0) {
2576 /* Let the interpreter deal with div by 0 */
2577 genInterpSingleStep(cUnit, mir);
2578 return false;
2579 }
2580 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2581 loadConstant(cUnit, r1, lit);
2582 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002583 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002584 storeValue(cUnit, r1, vDest, r2);
2585 break;
2586 default:
2587 return true;
2588 }
2589 return false;
2590}
2591
2592static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2593{
2594 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2595 int fieldOffset;
2596
2597 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2598 InstField *pInstField = (InstField *)
2599 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2600 int fieldOffset;
2601
2602 assert(pInstField != NULL);
2603 fieldOffset = pInstField->byteOffset;
2604 } else {
2605 /* To make the compiler happy */
2606 fieldOffset = 0;
2607 }
2608 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002609 case OP_NEW_ARRAY: {
2610 void *classPtr = (void*)
2611 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2612 assert(classPtr != NULL);
2613 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2614 loadConstant(cUnit, r0, (int) classPtr );
2615 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002616 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002617 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2618 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002619 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2620 opReg(cUnit, OP_BLX, r4PC);
2621 /* Note: on failure, we'll bail and reinterpret */
Ben Chenge9695e52009-06-16 16:11:47 -07002622 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002623 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2624 break;
2625 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002626 case OP_INSTANCE_OF: {
2627 ClassObject *classPtr =
2628 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2629 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002630 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002631 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002632//TUNING: compare to 0 primative to allow use of CB[N]Z
2633 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002634 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002635 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002636 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002637 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002638 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002639 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002640 opRegReg(cUnit, OP_CMP, r1, r2);
2641 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2642 opRegReg(cUnit, OP_MOV, r0, r1);
2643 opRegReg(cUnit, OP_MOV, r1, r2);
2644 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002645 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002646 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002647 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2648 branch1->generic.target = (LIR *)target;
2649 branch2->generic.target = (LIR *)target;
2650 break;
2651 }
2652 case OP_IGET_WIDE:
2653 genIGetWide(cUnit, mir, fieldOffset);
2654 break;
2655 case OP_IGET:
2656 case OP_IGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002657 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002658 break;
2659 case OP_IGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002660 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002661 break;
2662 case OP_IGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002663 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002664 break;
2665 case OP_IGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002666 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002667 break;
2668 case OP_IGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002669 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002670 break;
2671 case OP_IPUT_WIDE:
2672 genIPutWide(cUnit, mir, fieldOffset);
2673 break;
2674 case OP_IPUT:
2675 case OP_IPUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002676 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002677 break;
2678 case OP_IPUT_SHORT:
2679 case OP_IPUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002680 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002681 break;
2682 case OP_IPUT_BYTE:
2683 case OP_IPUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002684 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002685 break;
2686 default:
2687 return true;
2688 }
2689 return false;
2690}
2691
2692static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2693{
2694 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2695 int fieldOffset = mir->dalvikInsn.vC;
2696 switch (dalvikOpCode) {
2697 case OP_IGET_QUICK:
2698 case OP_IGET_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002699 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002700 break;
2701 case OP_IPUT_QUICK:
2702 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002703 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002704 break;
2705 case OP_IGET_WIDE_QUICK:
2706 genIGetWide(cUnit, mir, fieldOffset);
2707 break;
2708 case OP_IPUT_WIDE_QUICK:
2709 genIPutWide(cUnit, mir, fieldOffset);
2710 break;
2711 default:
2712 return true;
2713 }
2714 return false;
2715
2716}
2717
2718/* Compare agaist zero */
2719static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002720 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002721{
2722 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002723 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002724 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002725
Ben Chenge9695e52009-06-16 16:11:47 -07002726 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2727 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2728 reg1 = NEXT_REG(reg0);
2729 /* Load vB first since vA can be fetched via a move */
2730 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2731 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2732 } else {
2733 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2734 reg1 = NEXT_REG(reg0);
2735 /* Load vA first since vB can be fetched via a move */
2736 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2737 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2738 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002739 opRegReg(cUnit, OP_CMP, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002740
2741 switch (dalvikOpCode) {
2742 case OP_IF_EQ:
2743 cond = ARM_COND_EQ;
2744 break;
2745 case OP_IF_NE:
2746 cond = ARM_COND_NE;
2747 break;
2748 case OP_IF_LT:
2749 cond = ARM_COND_LT;
2750 break;
2751 case OP_IF_GE:
2752 cond = ARM_COND_GE;
2753 break;
2754 case OP_IF_GT:
2755 cond = ARM_COND_GT;
2756 break;
2757 case OP_IF_LE:
2758 cond = ARM_COND_LE;
2759 break;
2760 default:
2761 cond = 0;
2762 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2763 dvmAbort();
2764 }
2765 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2766 /* This mostly likely will be optimized away in a later phase */
2767 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2768 return false;
2769}
2770
2771static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2772{
2773 OpCode opCode = mir->dalvikInsn.opCode;
2774 int vSrc1Dest = mir->dalvikInsn.vA;
2775 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002776 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002777
2778 switch (opCode) {
2779 case OP_MOVE_16:
2780 case OP_MOVE_OBJECT_16:
2781 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002782 case OP_MOVE_OBJECT_FROM16: {
2783 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2784 reg1 = NEXT_REG(reg0);
2785 loadValue(cUnit, vSrc2, reg0);
2786 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002787 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002788 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002789 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002790 case OP_MOVE_WIDE_FROM16: {
2791 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2792 reg1 = NEXT_REG(reg0);
2793 reg2 = NEXT_REG(reg1);
2794 loadValuePair(cUnit, vSrc2, reg0, reg1);
2795 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002796 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002797 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002798 default:
2799 return true;
2800 }
2801 return false;
2802}
2803
2804static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2805{
2806 OpCode opCode = mir->dalvikInsn.opCode;
2807 int vA = mir->dalvikInsn.vA;
2808 int vB = mir->dalvikInsn.vB;
2809 int vC = mir->dalvikInsn.vC;
2810
Ben Chenge9695e52009-06-16 16:11:47 -07002811 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002812 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2813 return genArithOp( cUnit, mir );
2814 }
2815
2816 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002817 case OP_CMPL_FLOAT:
2818 case OP_CMPG_FLOAT:
2819 case OP_CMPL_DOUBLE:
2820 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002821 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002822 case OP_CMP_LONG:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07002823 genCmpLong(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002824 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002825 case OP_AGET_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002826 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002827 break;
2828 case OP_AGET:
2829 case OP_AGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002830 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002831 break;
2832 case OP_AGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002833 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002834 break;
2835 case OP_AGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002836 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002837 break;
2838 case OP_AGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002839 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002840 break;
2841 case OP_AGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002842 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002843 break;
2844 case OP_APUT_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002845 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002846 break;
2847 case OP_APUT:
2848 case OP_APUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002849 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002850 break;
2851 case OP_APUT_SHORT:
2852 case OP_APUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002853 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002854 break;
2855 case OP_APUT_BYTE:
2856 case OP_APUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002857 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002858 break;
2859 default:
2860 return true;
2861 }
2862 return false;
2863}
2864
2865static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2866{
2867 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2868 switch (dalvikOpCode) {
2869 case OP_FILL_ARRAY_DATA: {
2870 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2871 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2872 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2873 (int) (cUnit->method->insns + mir->offset));
2874 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002875 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002876 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002877 break;
2878 }
2879 /*
2880 * TODO
2881 * - Add a 1 to 3-entry per-location cache here to completely
2882 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2883 * - Use out-of-line handlers for both of these
2884 */
2885 case OP_PACKED_SWITCH:
2886 case OP_SPARSE_SWITCH: {
2887 if (dalvikOpCode == OP_PACKED_SWITCH) {
2888 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2889 } else {
2890 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2891 }
2892 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2893 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2894 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002895 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002896 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002897 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2898 jitToInterpEntries.dvmJitToInterpNoChain), r2);
2899 opRegReg(cUnit, OP_ADD, r0, r0);
2900 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
2901 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002902 break;
2903 }
2904 default:
2905 return true;
2906 }
2907 return false;
2908}
2909
2910static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002911 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002912{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07002913 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002914 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002915
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07002916 if (bb->fallThrough != NULL)
2917 retChainingCell = &labelList[bb->fallThrough->id];
2918
Ben Chengba4fc8b2009-06-01 13:00:29 -07002919 DecodedInstruction *dInsn = &mir->dalvikInsn;
2920 switch (mir->dalvikInsn.opCode) {
2921 /*
2922 * calleeMethod = this->clazz->vtable[
2923 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2924 * ]
2925 */
2926 case OP_INVOKE_VIRTUAL:
2927 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002928 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002929 int methodIndex =
2930 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2931 methodIndex;
2932
2933 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2934 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2935 else
2936 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2937
Ben Cheng38329f52009-07-07 14:19:20 -07002938 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2939 retChainingCell,
2940 predChainingCell,
2941 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002942 break;
2943 }
2944 /*
2945 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2946 * ->pResMethods[BBBB]->methodIndex]
2947 */
2948 /* TODO - not excersized in RunPerf.jar */
2949 case OP_INVOKE_SUPER:
2950 case OP_INVOKE_SUPER_RANGE: {
2951 int mIndex = cUnit->method->clazz->pDvmDex->
2952 pResMethods[dInsn->vB]->methodIndex;
2953 const Method *calleeMethod =
2954 cUnit->method->clazz->super->vtable[mIndex];
2955
2956 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2957 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2958 else
2959 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2960
2961 /* r0 = calleeMethod */
2962 loadConstant(cUnit, r0, (int) calleeMethod);
2963
Ben Cheng38329f52009-07-07 14:19:20 -07002964 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2965 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002966 break;
2967 }
2968 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2969 case OP_INVOKE_DIRECT:
2970 case OP_INVOKE_DIRECT_RANGE: {
2971 const Method *calleeMethod =
2972 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2973
2974 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2975 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2976 else
2977 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2978
2979 /* r0 = calleeMethod */
2980 loadConstant(cUnit, r0, (int) calleeMethod);
2981
Ben Cheng38329f52009-07-07 14:19:20 -07002982 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2983 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002984 break;
2985 }
2986 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2987 case OP_INVOKE_STATIC:
2988 case OP_INVOKE_STATIC_RANGE: {
2989 const Method *calleeMethod =
2990 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2991
2992 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2993 genProcessArgsNoRange(cUnit, mir, dInsn,
2994 NULL /* no null check */);
2995 else
2996 genProcessArgsRange(cUnit, mir, dInsn,
2997 NULL /* no null check */);
2998
2999 /* r0 = calleeMethod */
3000 loadConstant(cUnit, r0, (int) calleeMethod);
3001
Ben Cheng38329f52009-07-07 14:19:20 -07003002 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3003 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003004 break;
3005 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07003006/*
3007 * TODO: When we move to using upper registers in Thumb2, make sure
3008 * the register allocater is told that r9, r10, & r12 are killed
3009 * here.
3010 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003011 /*
3012 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3013 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003014 *
3015 * Given "invoke-interface {v0}", the following is the generated code:
3016 *
3017 * 0x426a9abe : ldr r0, [r5, #0] --+
3018 * 0x426a9ac0 : mov r7, r5 |
3019 * 0x426a9ac2 : sub r7, #24 |
3020 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3021 * 0x426a9ac6 : beq 0x426a9afe |
3022 * 0x426a9ac8 : stmia r7, <r0> --+
3023 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3024 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3025 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3026 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3027 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3028 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3029 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
3030 * 0x426a9ad8 : mov r9, r1 --+
3031 * 0x426a9ada : mov r10, r2 |
3032 * 0x426a9adc : mov r12, r3 |
3033 * 0x426a9ade : mov r0, r3 |
3034 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3035 * 0x426a9ae2 : ldr r2, [pc, #76] |
3036 * 0x426a9ae4 : ldr r3, [pc, #68] |
3037 * 0x426a9ae6 : ldr r7, [pc, #64] |
3038 * 0x426a9ae8 : blx r7 --+
3039 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
3040 * 0x426a9aec : cmp r1, #0 --> compare against 0
3041 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3042 * 0x426a9af0 : ldr r7, [r6, #96] --+
3043 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3044 * 0x426a9af4 : mov r3, r12 |
3045 * 0x426a9af6 : blx r7 --+
3046 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3047 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3048 * 0x426a9afc : blx_2 see above --+
3049 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3050 * 0x426a9afe (0042): ldr r0, [pc, #52]
3051 * Exception_Handling:
3052 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3053 * 0x426a9b02 (0046): blx r1
3054 * 0x426a9b04 (0048): .align4
3055 * -------- chaining cell (hot): 0x0021
3056 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3057 * 0x426a9b06 (004a): blx r0
3058 * 0x426a9b08 (004c): data 0x7872(30834)
3059 * 0x426a9b0a (004e): data 0x428b(17035)
3060 * 0x426a9b0c (0050): .align4
3061 * -------- chaining cell (predicted)
3062 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3063 * 0x426a9b0e (0052): data 0x0000(0)
3064 * 0x426a9b10 (0054): data 0x0000(0) --> class
3065 * 0x426a9b12 (0056): data 0x0000(0)
3066 * 0x426a9b14 (0058): data 0x0000(0) --> method
3067 * 0x426a9b16 (005a): data 0x0000(0)
3068 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3069 * 0x426a9b1a (005e): data 0x0000(0)
3070 * 0x426a9b28 (006c): .word (0xad0392a5)
3071 * 0x426a9b2c (0070): .word (0x6e750)
3072 * 0x426a9b30 (0074): .word (0x4109a618)
3073 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003074 */
3075 case OP_INVOKE_INTERFACE:
3076 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003077 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003078 int methodIndex = dInsn->vB;
3079
3080 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3081 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3082 else
3083 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3084
Ben Cheng38329f52009-07-07 14:19:20 -07003085 /* "this" is already left in r0 by genProcessArgs* */
3086
3087 /* r4PC = dalvikCallsite */
3088 loadConstant(cUnit, r4PC,
3089 (int) (cUnit->method->insns + mir->offset));
3090
3091 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003092 ArmLIR *addrRetChain =
3093 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003094 addrRetChain->generic.target = (LIR *) retChainingCell;
3095
3096 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003097 ArmLIR *predictedChainingCell =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003098 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003099 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3100
3101 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3102
3103 /* return through lr - jump to the chaining cell */
3104 genUnconditionalBranch(cUnit, predChainingCell);
3105
3106 /*
3107 * null-check on "this" may have been eliminated, but we still need
3108 * a PC-reconstruction label for stack overflow bailout.
3109 */
3110 if (pcrLabel == NULL) {
3111 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003112 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3113 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003114 pcrLabel->operands[0] = dPC;
3115 pcrLabel->operands[1] = mir->offset;
3116 /* Insert the place holder to the growable list */
3117 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3118 }
3119
3120 /* return through lr+2 - punt to the interpreter */
3121 genUnconditionalBranch(cUnit, pcrLabel);
3122
3123 /*
3124 * return through lr+4 - fully resolve the callee method.
3125 * r1 <- count
3126 * r2 <- &predictedChainCell
3127 * r3 <- this->class
3128 * r4 <- dPC
3129 * r7 <- this->class->vtable
3130 */
3131
3132 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003133 opRegReg(cUnit, OP_MOV, r9, r1);
3134 opRegReg(cUnit, OP_MOV, r10, r2);
3135 opRegReg(cUnit, OP_MOV, r12, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003136
Ben Chengba4fc8b2009-06-01 13:00:29 -07003137 /* r0 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003138 opRegReg(cUnit, OP_MOV, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003139
3140 /* r1 = BBBB */
3141 loadConstant(cUnit, r1, dInsn->vB);
3142
3143 /* r2 = method (caller) */
3144 loadConstant(cUnit, r2, (int) cUnit->method);
3145
3146 /* r3 = pDvmDex */
3147 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3148
3149 loadConstant(cUnit, r7,
3150 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003151 opReg(cUnit, OP_BLX, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003152
3153 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3154
Bill Buzbee270c1d62009-08-13 16:58:07 -07003155 opRegReg(cUnit, OP_MOV, r1, r9);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003156
Ben Cheng38329f52009-07-07 14:19:20 -07003157 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003158 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003159
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003160 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003161 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07003162
Bill Buzbee270c1d62009-08-13 16:58:07 -07003163 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3164 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003165
Bill Buzbee270c1d62009-08-13 16:58:07 -07003166 opRegReg(cUnit, OP_MOV, r2, r10);
3167 opRegReg(cUnit, OP_MOV, r3, r12);
Ben Cheng38329f52009-07-07 14:19:20 -07003168
3169 /*
3170 * r0 = calleeMethod
3171 * r2 = &predictedChainingCell
3172 * r3 = class
3173 *
3174 * &returnChainingCell has been loaded into r1 but is not needed
3175 * when patching the chaining cell and will be clobbered upon
3176 * returning so it will be reconstructed again.
3177 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003178 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003179
3180 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003181 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003182 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003183
3184 bypassRechaining->generic.target = (LIR *) addrRetChain;
3185
Ben Chengba4fc8b2009-06-01 13:00:29 -07003186 /*
3187 * r0 = this, r1 = calleeMethod,
3188 * r1 = &ChainingCell,
3189 * r4PC = callsiteDPC,
3190 */
3191 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3192#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003193 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003194#endif
3195 /* Handle exceptions using the interpreter */
3196 genTrap(cUnit, mir->offset, pcrLabel);
3197 break;
3198 }
3199 /* NOP */
3200 case OP_INVOKE_DIRECT_EMPTY: {
3201 return false;
3202 }
3203 case OP_FILLED_NEW_ARRAY:
3204 case OP_FILLED_NEW_ARRAY_RANGE: {
3205 /* Just let the interpreter deal with these */
3206 genInterpSingleStep(cUnit, mir);
3207 break;
3208 }
3209 default:
3210 return true;
3211 }
3212 return false;
3213}
3214
3215static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003216 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003217{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003218 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3219 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3220 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003221
3222 DecodedInstruction *dInsn = &mir->dalvikInsn;
3223 switch (mir->dalvikInsn.opCode) {
3224 /* calleeMethod = this->clazz->vtable[BBBB] */
3225 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3226 case OP_INVOKE_VIRTUAL_QUICK: {
3227 int methodIndex = dInsn->vB;
3228 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3229 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3230 else
3231 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3232
Ben Cheng38329f52009-07-07 14:19:20 -07003233 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3234 retChainingCell,
3235 predChainingCell,
3236 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003237 break;
3238 }
3239 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3240 case OP_INVOKE_SUPER_QUICK:
3241 case OP_INVOKE_SUPER_QUICK_RANGE: {
3242 const Method *calleeMethod =
3243 cUnit->method->clazz->super->vtable[dInsn->vB];
3244
3245 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3246 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3247 else
3248 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3249
3250 /* r0 = calleeMethod */
3251 loadConstant(cUnit, r0, (int) calleeMethod);
3252
Ben Cheng38329f52009-07-07 14:19:20 -07003253 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3254 calleeMethod);
3255 /* Handle exceptions using the interpreter */
3256 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003257 break;
3258 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003259 default:
3260 return true;
3261 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003262 return false;
3263}
3264
3265/*
3266 * NOTE: We assume here that the special native inline routines
3267 * are side-effect free. By making this assumption, we can safely
3268 * re-execute the routine from the interpreter if it decides it
3269 * wants to throw an exception. We still need to EXPORT_PC(), though.
3270 */
3271static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3272{
3273 DecodedInstruction *dInsn = &mir->dalvikInsn;
3274 switch( mir->dalvikInsn.opCode) {
3275 case OP_EXECUTE_INLINE: {
3276 unsigned int i;
3277 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003278 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003279 int operation = dInsn->vB;
3280
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003281 switch (operation) {
3282 case INLINE_EMPTYINLINEMETHOD:
3283 return false; /* Nop */
3284 case INLINE_STRING_LENGTH:
3285 return genInlinedStringLength(cUnit, mir);
3286 case INLINE_MATH_ABS_INT:
3287 return genInlinedAbsInt(cUnit, mir);
3288 case INLINE_MATH_ABS_LONG:
3289 return genInlinedAbsLong(cUnit, mir);
3290 case INLINE_MATH_MIN_INT:
3291 return genInlinedMinMaxInt(cUnit, mir, true);
3292 case INLINE_MATH_MAX_INT:
3293 return genInlinedMinMaxInt(cUnit, mir, false);
3294 case INLINE_STRING_CHARAT:
3295 return genInlinedStringCharAt(cUnit, mir);
3296 case INLINE_MATH_SQRT:
3297 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003298 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003299 else
3300 break; /* Handle with C routine */
3301 case INLINE_MATH_COS:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003302 case INLINE_MATH_SIN:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003303 break; /* Handle with C routine */
3304 case INLINE_MATH_ABS_FLOAT:
3305 return genInlinedAbsFloat(cUnit, mir);
3306 case INLINE_MATH_ABS_DOUBLE:
3307 return genInlinedAbsDouble(cUnit, mir);
3308 case INLINE_STRING_COMPARETO:
3309 case INLINE_STRING_EQUALS:
Bill Buzbee12ba0152009-09-03 14:03:09 -07003310 case INLINE_STRING_INDEXOF_I:
3311 case INLINE_STRING_INDEXOF_II:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003312 break;
3313 default:
3314 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003315 }
3316
3317 /* Materialize pointer to retval & push */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003318 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3319 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3320
Ben Chengba4fc8b2009-06-01 13:00:29 -07003321 /* Push r4 and (just to take up space) r5) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003322 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003323
3324 /* Get code pointer to inline routine */
3325 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3326
3327 /* Export PC */
3328 genExportPC(cUnit, mir, r0, r1 );
3329
3330 /* Load arguments to r0 through r3 as applicable */
3331 for (i=0; i < dInsn->vA; i++) {
3332 loadValue(cUnit, dInsn->arg[i], i);
3333 }
3334 /* Call inline routine */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003335 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003336
3337 /* Strip frame */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003338 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003339
3340 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003341 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003342
Ben Chenge9695e52009-06-16 16:11:47 -07003343 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003344 break;
3345 }
3346 default:
3347 return true;
3348 }
3349 return false;
3350}
3351
3352static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3353{
3354 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3355 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3356 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3357 return false;
3358}
3359
Ben Chengba4fc8b2009-06-01 13:00:29 -07003360/*
3361 * The following are special processing routines that handle transfer of
3362 * controls between compiled code and the interpreter. Certain VM states like
3363 * Dalvik PC and special-purpose registers are reconstructed here.
3364 */
3365
Ben Cheng1efc9c52009-06-08 18:25:27 -07003366/* Chaining cell for code that may need warmup. */
3367static void handleNormalChainingCell(CompilationUnit *cUnit,
3368 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003369{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003370 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3371 jitToInterpEntries.dvmJitToInterpNormal), r0);
3372 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003373 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3374}
3375
3376/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003377 * Chaining cell for instructions that immediately following already translated
3378 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003379 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003380static void handleHotChainingCell(CompilationUnit *cUnit,
3381 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003382{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003383 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3384 jitToInterpEntries.dvmJitToTraceSelect), r0);
3385 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003386 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3387}
3388
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003389#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003390/* Chaining cell for branches that branch back into the same basic block */
3391static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3392 unsigned int offset)
3393{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003394#if defined(WITH_SELF_VERIFICATION)
Jeff Hao97319a82009-08-12 16:57:15 -07003395 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3396 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003397#else
3398 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3399 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3400#endif
Jeff Hao97319a82009-08-12 16:57:15 -07003401 newLIR1(cUnit, THUMB_BLX_R, r0);
3402 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3403}
3404
3405#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003406/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003407static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3408 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003409{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003410 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3411 jitToInterpEntries.dvmJitToTraceSelect), r0);
3412 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003413 addWordData(cUnit, (int) (callee->insns), true);
3414}
3415
Ben Cheng38329f52009-07-07 14:19:20 -07003416/* Chaining cell for monomorphic method invocations. */
3417static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3418{
3419
3420 /* Should not be executed in the initial state */
3421 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3422 /* To be filled: class */
3423 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3424 /* To be filled: method */
3425 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3426 /*
3427 * Rechain count. The initial value of 0 here will trigger chaining upon
3428 * the first invocation of this callsite.
3429 */
3430 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3431}
3432
Ben Chengba4fc8b2009-06-01 13:00:29 -07003433/* Load the Dalvik PC into r0 and jump to the specified target */
3434static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003435 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003436{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003437 ArmLIR **pcrLabel =
3438 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003439 int numElems = cUnit->pcReconstructionList.numUsed;
3440 int i;
3441 for (i = 0; i < numElems; i++) {
3442 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3443 /* r0 = dalvik PC */
3444 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3445 genUnconditionalBranch(cUnit, targetLabel);
3446 }
3447}
3448
Ben Cheng4238ec22009-08-24 16:32:22 -07003449static char *extendedMIROpNames[MIR_OP_LAST - MIR_OP_FIRST] = {
3450 "MIR_OP_PHI",
3451 "MIR_OP_NULL_N_RANGE_UP_CHECK",
3452 "MIR_OP_NULL_N_RANGE_DOWN_CHECK",
3453 "MIR_OP_LOWER_BOUND_CHECK",
3454 "MIR_OP_PUNT",
3455};
3456
3457/*
3458 * vA = arrayReg;
3459 * vB = idxReg;
3460 * vC = endConditionReg;
3461 * arg[0] = maxC
3462 * arg[1] = minC
3463 * arg[2] = loopBranchConditionCode
3464 */
3465static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3466{
3467 DecodedInstruction *dInsn = &mir->dalvikInsn;
3468 const int lenOffset = offsetof(ArrayObject, length);
3469 const int regArray = 0;
3470 const int regIdxEnd = NEXT_REG(regArray);
3471 const int regLength = regArray;
3472 const int maxC = dInsn->arg[0];
3473 const int minC = dInsn->arg[1];
3474
3475 /* regArray <- arrayRef */
3476 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3477 loadValue(cUnit, mir->dalvikInsn.vC, regIdxEnd);
3478 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3479 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3480
3481 /* regLength <- len(arrayRef) */
3482 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3483
3484 int delta = maxC;
3485 /*
3486 * If the loop end condition is ">=" instead of ">", then the largest value
3487 * of the index is "endCondition - 1".
3488 */
3489 if (dInsn->arg[2] == OP_IF_GE) {
3490 delta--;
3491 }
3492
3493 if (delta) {
3494 opRegImm(cUnit, OP_ADD, regIdxEnd, delta, regIdxEnd);
3495 }
3496 /* Punt if "regIdxEnd < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003497 genRegRegCheck(cUnit, ARM_COND_GE, regIdxEnd, regLength, 0,
3498 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003499}
3500
3501/*
3502 * vA = arrayReg;
3503 * vB = idxReg;
3504 * vC = endConditionReg;
3505 * arg[0] = maxC
3506 * arg[1] = minC
3507 * arg[2] = loopBranchConditionCode
3508 */
3509static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3510{
3511 DecodedInstruction *dInsn = &mir->dalvikInsn;
3512 const int lenOffset = offsetof(ArrayObject, length);
3513 const int regArray = 0;
3514 const int regIdxInit = NEXT_REG(regArray);
3515 const int regLength = regArray;
3516 const int maxC = dInsn->arg[0];
3517 const int minC = dInsn->arg[1];
3518
3519 /* regArray <- arrayRef */
3520 loadValue(cUnit, mir->dalvikInsn.vA, regArray);
3521 loadValue(cUnit, mir->dalvikInsn.vB, regIdxInit);
3522 genRegImmCheck(cUnit, ARM_COND_EQ, regArray, 0, 0,
3523 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3524
3525 /* regLength <- len(arrayRef) */
3526 loadWordDisp(cUnit, regArray, lenOffset, regLength);
3527
3528 if (maxC) {
3529 opRegImm(cUnit, OP_ADD, regIdxInit, maxC, regIdxInit);
3530 }
3531
3532 /* Punt if "regIdxInit < len(Array)" is false */
Ben Cheng0fd31e42009-09-03 14:40:16 -07003533 genRegRegCheck(cUnit, ARM_COND_GE, regIdxInit, regLength, 0,
3534 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003535}
3536
3537/*
3538 * vA = idxReg;
3539 * vB = minC;
3540 */
3541static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3542{
3543 DecodedInstruction *dInsn = &mir->dalvikInsn;
3544 const int regIdx = 0;
3545 const int minC = dInsn->vB;
3546
3547 /* regIdx <- initial index value */
3548 loadValue(cUnit, mir->dalvikInsn.vA, regIdx);
3549
3550 /* Punt if "regIdxInit + minC >= 0" is false */
3551 genRegImmCheck(cUnit, ARM_COND_LT, regIdx, -minC, 0,
3552 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3553}
3554
3555/* Extended MIR instructions like PHI */
3556static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3557{
3558 int opOffset = mir->dalvikInsn.opCode - MIR_OP_FIRST;
3559 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3560 false);
3561 strcpy(msg, extendedMIROpNames[opOffset]);
3562 newLIR1(cUnit, ARM_PSEUDO_EXTENDED_MIR, (int) msg);
3563
3564 switch (mir->dalvikInsn.opCode) {
3565 case MIR_OP_PHI: {
3566 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3567 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3568 break;
3569 }
3570 case MIR_OP_NULL_N_RANGE_UP_CHECK: {
3571 genHoistedChecksForCountUpLoop(cUnit, mir);
3572 break;
3573 }
3574 case MIR_OP_NULL_N_RANGE_DOWN_CHECK: {
3575 genHoistedChecksForCountDownLoop(cUnit, mir);
3576 break;
3577 }
3578 case MIR_OP_LOWER_BOUND_CHECK: {
3579 genHoistedLowerBoundCheck(cUnit, mir);
3580 break;
3581 }
3582 case MIR_OP_PUNT: {
3583 genUnconditionalBranch(cUnit,
3584 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3585 break;
3586 }
3587 default:
3588 break;
3589 }
3590}
3591
3592/*
3593 * Create a PC-reconstruction cell for the starting offset of this trace.
3594 * Since the PCR cell is placed near the end of the compiled code which is
3595 * usually out of range for a conditional branch, we put two branches (one
3596 * branch over to the loop body and one layover branch to the actual PCR) at the
3597 * end of the entry block.
3598 */
3599static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
3600 ArmLIR *bodyLabel)
3601{
3602 /* Set up the place holder to reconstruct this Dalvik PC */
3603 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3604 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
3605 pcrLabel->operands[0] =
3606 (int) (cUnit->method->insns + entry->startOffset);
3607 pcrLabel->operands[1] = entry->startOffset;
3608 /* Insert the place holder to the growable list */
3609 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3610
3611 /*
3612 * Next, create two branches - one branch over to the loop body and the
3613 * other branch to the PCR cell to punt.
3614 */
3615 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
3616 branchToBody->opCode = THUMB_B_UNCOND;
3617 branchToBody->generic.target = (LIR *) bodyLabel;
3618 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
3619
3620 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
3621 branchToPCR->opCode = THUMB_B_UNCOND;
3622 branchToPCR->generic.target = (LIR *) pcrLabel;
3623 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
3624}
3625
Ben Chengba4fc8b2009-06-01 13:00:29 -07003626void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3627{
3628 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003629 ArmLIR *labelList =
3630 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003631 GrowableList chainingListByType[CHAINING_CELL_LAST];
3632 int i;
3633
3634 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003635 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003636 */
3637 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3638 dvmInitGrowableList(&chainingListByType[i], 2);
3639 }
3640
3641 BasicBlock **blockList = cUnit->blockList;
3642
Bill Buzbee6e963e12009-06-17 16:56:19 -07003643 if (cUnit->executionCount) {
3644 /*
3645 * Reserve 6 bytes at the beginning of the trace
3646 * +----------------------------+
3647 * | execution count (4 bytes) |
3648 * +----------------------------+
3649 * | chain cell offset (2 bytes)|
3650 * +----------------------------+
3651 * ...and then code to increment the execution
3652 * count:
3653 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3654 * sub r0, #10 @ back up to addr of executionCount
3655 * ldr r1, [r0]
3656 * add r1, #1
3657 * str r1, [r0]
3658 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003659 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3660 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003661 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003662 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003663 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003664 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003665 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc & THUMB_REG_MASK);
3666 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3667 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3668 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3669 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003670 } else {
3671 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003672 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003673 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003674 cUnit->headerSize = 2;
3675 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003676
Ben Chengba4fc8b2009-06-01 13:00:29 -07003677 /* Handle the content in each basic block */
3678 for (i = 0; i < cUnit->numBlocks; i++) {
3679 blockList[i]->visited = true;
3680 MIR *mir;
3681
3682 labelList[i].operands[0] = blockList[i]->startOffset;
3683
3684 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3685 /*
3686 * Append the label pseudo LIR first. Chaining cells will be handled
3687 * separately afterwards.
3688 */
3689 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3690 }
3691
Ben Cheng4238ec22009-08-24 16:32:22 -07003692 if (blockList[i]->blockType == ENTRY_BLOCK) {
3693 labelList[i].opCode = ARM_PSEUDO_ENTRY_BLOCK;
3694 if (blockList[i]->firstMIRInsn == NULL) {
3695 continue;
3696 } else {
3697 setupLoopEntryBlock(cUnit, blockList[i],
3698 &labelList[blockList[i]->fallThrough->id]);
3699 }
3700 } else if (blockList[i]->blockType == EXIT_BLOCK) {
3701 labelList[i].opCode = ARM_PSEUDO_EXIT_BLOCK;
3702 goto gen_fallthrough;
3703 } else if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003704 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003705 /* Reset the register state */
3706 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003707 } else {
3708 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003709 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003710 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003711 /* handle the codegen later */
3712 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003713 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003714 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003715 case CHAINING_CELL_INVOKE_SINGLETON:
3716 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003717 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003718 labelList[i].operands[0] =
3719 (int) blockList[i]->containingMethod;
3720 /* handle the codegen later */
3721 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003722 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3723 (void *) i);
3724 break;
3725 case CHAINING_CELL_INVOKE_PREDICTED:
3726 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003727 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003728 /* handle the codegen later */
3729 dvmInsertGrowableList(
3730 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3731 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003732 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003733 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003734 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003735 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003736 /* handle the codegen later */
3737 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003738 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003739 (void *) i);
3740 break;
3741 case PC_RECONSTRUCTION:
3742 /* Make sure exception handling block is next */
3743 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003744 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003745 assert (i == cUnit->numBlocks - 2);
3746 handlePCReconstruction(cUnit, &labelList[i+1]);
3747 break;
3748 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003749 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003750 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003751 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3752 jitToInterpEntries.dvmJitToInterpPunt),
3753 r1);
3754 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003755 }
3756 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003757#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003758 case CHAINING_CELL_BACKWARD_BRANCH:
3759 labelList[i].opCode =
3760 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3761 /* handle the codegen later */
3762 dvmInsertGrowableList(
3763 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3764 (void *) i);
3765 break;
3766#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003767 default:
3768 break;
3769 }
3770 continue;
3771 }
Ben Chenge9695e52009-06-16 16:11:47 -07003772
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003773 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003774
Ben Chengba4fc8b2009-06-01 13:00:29 -07003775 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Ben Cheng4238ec22009-08-24 16:32:22 -07003776 if (mir->dalvikInsn.opCode >= MIR_OP_FIRST) {
3777 handleExtendedMIR(cUnit, mir);
3778 continue;
3779 }
3780
Ben Chengba4fc8b2009-06-01 13:00:29 -07003781 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3782 InstructionFormat dalvikFormat =
3783 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003784 ArmLIR *boundaryLIR =
3785 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Cheng4238ec22009-08-24 16:32:22 -07003786 mir->offset, dalvikOpCode);
3787 if (mir->ssaRep) {
3788 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
3789 newLIR1(cUnit, ARM_PSEUDO_SSA_REP, (int) ssaString);
3790 }
3791
Ben Chenge9695e52009-06-16 16:11:47 -07003792 /* Remember the first LIR for this block */
3793 if (headLIR == NULL) {
3794 headLIR = boundaryLIR;
3795 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003796
Ben Chengba4fc8b2009-06-01 13:00:29 -07003797 bool notHandled;
3798 /*
3799 * Debugging: screen the opcode first to see if it is in the
3800 * do[-not]-compile list
3801 */
3802 bool singleStepMe =
3803 gDvmJit.includeSelectedOp !=
3804 ((gDvmJit.opList[dalvikOpCode >> 3] &
3805 (1 << (dalvikOpCode & 0x7))) !=
3806 0);
Jeff Hao97319a82009-08-12 16:57:15 -07003807#if defined(WITH_SELF_VERIFICATION)
3808 /* Punt on opcodes we can't replay */
3809 if (selfVerificationPuntOps(dalvikOpCode))
3810 singleStepMe = true;
3811#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003812 if (singleStepMe || cUnit->allSingleStep) {
3813 notHandled = false;
3814 genInterpSingleStep(cUnit, mir);
3815 } else {
3816 opcodeCoverage[dalvikOpCode]++;
3817 switch (dalvikFormat) {
3818 case kFmt10t:
3819 case kFmt20t:
3820 case kFmt30t:
3821 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3822 mir, blockList[i], labelList);
3823 break;
3824 case kFmt10x:
3825 notHandled = handleFmt10x(cUnit, mir);
3826 break;
3827 case kFmt11n:
3828 case kFmt31i:
3829 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3830 break;
3831 case kFmt11x:
3832 notHandled = handleFmt11x(cUnit, mir);
3833 break;
3834 case kFmt12x:
3835 notHandled = handleFmt12x(cUnit, mir);
3836 break;
3837 case kFmt20bc:
3838 notHandled = handleFmt20bc(cUnit, mir);
3839 break;
3840 case kFmt21c:
3841 case kFmt31c:
3842 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3843 break;
3844 case kFmt21h:
3845 notHandled = handleFmt21h(cUnit, mir);
3846 break;
3847 case kFmt21s:
3848 notHandled = handleFmt21s(cUnit, mir);
3849 break;
3850 case kFmt21t:
3851 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3852 labelList);
3853 break;
3854 case kFmt22b:
3855 case kFmt22s:
3856 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3857 break;
3858 case kFmt22c:
3859 notHandled = handleFmt22c(cUnit, mir);
3860 break;
3861 case kFmt22cs:
3862 notHandled = handleFmt22cs(cUnit, mir);
3863 break;
3864 case kFmt22t:
3865 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3866 labelList);
3867 break;
3868 case kFmt22x:
3869 case kFmt32x:
3870 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3871 break;
3872 case kFmt23x:
3873 notHandled = handleFmt23x(cUnit, mir);
3874 break;
3875 case kFmt31t:
3876 notHandled = handleFmt31t(cUnit, mir);
3877 break;
3878 case kFmt3rc:
3879 case kFmt35c:
3880 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3881 labelList);
3882 break;
3883 case kFmt3rms:
3884 case kFmt35ms:
3885 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3886 labelList);
3887 break;
3888 case kFmt3inline:
3889 notHandled = handleFmt3inline(cUnit, mir);
3890 break;
3891 case kFmt51l:
3892 notHandled = handleFmt51l(cUnit, mir);
3893 break;
3894 default:
3895 notHandled = true;
3896 break;
3897 }
3898 }
3899 if (notHandled) {
3900 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3901 mir->offset,
3902 dalvikOpCode, getOpcodeName(dalvikOpCode),
3903 dalvikFormat);
3904 dvmAbort();
3905 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003906 }
3907 }
Ben Cheng4238ec22009-08-24 16:32:22 -07003908
3909 if (blockList[i]->blockType == ENTRY_BLOCK) {
3910 dvmCompilerAppendLIR(cUnit,
3911 (LIR *) cUnit->loopAnalysis->branchToBody);
3912 dvmCompilerAppendLIR(cUnit,
3913 (LIR *) cUnit->loopAnalysis->branchToPCR);
3914 }
3915
3916 if (headLIR) {
3917 /*
3918 * Eliminate redundant loads/stores and delay stores into later
3919 * slots
3920 */
3921 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3922 cUnit->lastLIRInsn);
3923 }
3924
3925gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003926 /*
3927 * Check if the block is terminated due to trace length constraint -
3928 * insert an unconditional branch to the chaining cell.
3929 */
3930 if (blockList[i]->needFallThroughBranch) {
3931 genUnconditionalBranch(cUnit,
3932 &labelList[blockList[i]->fallThrough->id]);
3933 }
3934
Ben Chengba4fc8b2009-06-01 13:00:29 -07003935 }
3936
Ben Chenge9695e52009-06-16 16:11:47 -07003937 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003938 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3939 size_t j;
3940 int *blockIdList = (int *) chainingListByType[i].elemList;
3941
3942 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3943
3944 /* No chaining cells of this type */
3945 if (cUnit->numChainingCells[i] == 0)
3946 continue;
3947
3948 /* Record the first LIR for a new type of chaining cell */
3949 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3950
3951 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3952 int blockId = blockIdList[j];
3953
3954 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003955 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003956
3957 /* Insert the pseudo chaining instruction */
3958 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3959
3960
3961 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003962 case CHAINING_CELL_NORMAL:
3963 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003964 blockList[blockId]->startOffset);
3965 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003966 case CHAINING_CELL_INVOKE_SINGLETON:
3967 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003968 blockList[blockId]->containingMethod);
3969 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003970 case CHAINING_CELL_INVOKE_PREDICTED:
3971 handleInvokePredictedChainingCell(cUnit);
3972 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003973 case CHAINING_CELL_HOT:
3974 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003975 blockList[blockId]->startOffset);
3976 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003977#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003978 case CHAINING_CELL_BACKWARD_BRANCH:
3979 handleBackwardBranchChainingCell(cUnit,
3980 blockList[blockId]->startOffset);
3981 break;
3982#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003983 default:
3984 dvmAbort();
3985 break;
3986 }
3987 }
3988 }
Ben Chenge9695e52009-06-16 16:11:47 -07003989
3990 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003991}
3992
3993/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07003994bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003995{
Bill Buzbee716f1202009-07-23 13:22:09 -07003996 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003997
3998 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07003999 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004000 }
4001
4002 switch (work->kind) {
4003 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07004004 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004005 break;
4006 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004007 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07004008 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004009 break;
4010 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07004011 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004012 dvmAbort();
4013 }
4014 return res;
4015}
4016
Ben Chengba4fc8b2009-06-01 13:00:29 -07004017/* Architectural-specific debugging helpers go here */
4018void dvmCompilerArchDump(void)
4019{
4020 /* Print compiled opcode in this VM instance */
4021 int i, start, streak;
4022 char buf[1024];
4023
4024 streak = i = 0;
4025 buf[0] = 0;
4026 while (opcodeCoverage[i] == 0 && i < 256) {
4027 i++;
4028 }
4029 if (i == 256) {
4030 return;
4031 }
4032 for (start = i++, streak = 1; i < 256; i++) {
4033 if (opcodeCoverage[i]) {
4034 streak++;
4035 } else {
4036 if (streak == 1) {
4037 sprintf(buf+strlen(buf), "%x,", start);
4038 } else {
4039 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4040 }
4041 streak = 0;
4042 while (opcodeCoverage[i] == 0 && i < 256) {
4043 i++;
4044 }
4045 if (i < 256) {
4046 streak = 1;
4047 start = i;
4048 }
4049 }
4050 }
4051 if (streak) {
4052 if (streak == 1) {
4053 sprintf(buf+strlen(buf), "%x", start);
4054 } else {
4055 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4056 }
4057 }
4058 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004059 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004060 }
4061}