blob: d9a29e814a48d7c0c9c564f9fd61d60d793d6d0a [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 Chengba4fc8b2009-06-01 13:00:29 -070027
Ben Chengba4fc8b2009-06-01 13:00:29 -070028/* Array holding the entry offset of each template relative to the first one */
29static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
30
31/* Track exercised opcodes */
32static int opcodeCoverage[256];
33
Jeff Hao97319a82009-08-12 16:57:15 -070034#if defined(WITH_SELF_VERIFICATION)
35/* Prevent certain opcodes from being jitted */
36static inline bool selfVerificationPuntOps(OpCode op)
37{
38 return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT ||
39 op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY);
40}
41
42/*
43 * The following are used to keep compiled loads and stores from modifying
44 * memory during self verification mode.
45 *
46 * Stores do not modify memory. Instead, the address and value pair are stored
47 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
48 * than a word, the word containing the address is loaded first before being
49 * updated.
50 *
51 * Loads check heapSpace first and return data from there if an entry exists.
52 * Otherwise, data is loaded from memory as usual.
53 */
54
55/* Decode contents of heapArgSpace to determine addr to load from */
56static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
57{
58 int reg = heapArgSpace->regMap & 0xF;
59
60 switch (reg) {
61 case 0:
62 *addr = heapArgSpace->r0;
63 break;
64 case 1:
65 *addr = heapArgSpace->r1;
66 break;
67 case 2:
68 *addr = heapArgSpace->r2;
69 break;
70 case 3:
71 *addr = heapArgSpace->r3;
72 break;
73 default:
74 LOGE("ERROR: bad reg used in selfVerificationLoadDecode: %d", reg);
75 break;
76 }
77}
78
79/* Decode contents of heapArgSpace to determine reg to load into */
80static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
81 int data, int reg)
82{
83 switch (reg) {
84 case 0:
85 heapArgSpace->r0 = data;
86 break;
87 case 1:
88 heapArgSpace->r1 = data;
89 break;
90 case 2:
91 heapArgSpace->r2 = data;
92 break;
93 case 3:
94 heapArgSpace->r3 = data;
95 break;
96 default:
97 LOGE("ERROR: bad reg passed to selfVerificationLoadDecodeData: %d",
98 reg);
99 break;
100 }
101}
102
103static void selfVerificationLoad(InterpState* interpState)
104{
105 Thread *self = dvmThreadSelf();
106 ShadowHeap *heapSpacePtr;
107 ShadowSpace *shadowSpace = self->shadowSpace;
108 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
109
110 int addr, data;
111 selfVerificationLoadDecode(heapArgSpace, &addr);
112
113 for (heapSpacePtr = shadowSpace->heapSpace;
114 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
115 if (heapSpacePtr->addr == addr) {
116 data = heapSpacePtr->data;
117 break;
118 }
119 }
120
121 if (heapSpacePtr == shadowSpace->heapSpaceTail)
122 data = *((unsigned int*) addr);
123
124 //LOGD("*** HEAP LOAD: Addr: 0x%x Data: 0x%x", addr, data);
125
126 int reg = (heapArgSpace->regMap >> 4) & 0xF;
127 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
128}
129
130static void selfVerificationLoadByte(InterpState* interpState)
131{
132 Thread *self = dvmThreadSelf();
133 ShadowHeap *heapSpacePtr;
134 ShadowSpace *shadowSpace = self->shadowSpace;
135 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
136
137 int addr, data;
138 selfVerificationLoadDecode(heapArgSpace, &addr);
139
140 int maskedAddr = addr & 0xFFFFFFFC;
141 int alignment = addr & 0x3;
142
143 for (heapSpacePtr = shadowSpace->heapSpace;
144 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
145 if (heapSpacePtr->addr == maskedAddr) {
146 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
147 data = *((unsigned char*) addr);
148 break;
149 }
150 }
151
152 if (heapSpacePtr == shadowSpace->heapSpaceTail)
153 data = *((unsigned char*) addr);
154
155 //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
156
157 int reg = (heapArgSpace->regMap >> 4) & 0xF;
158 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
159}
160
161static void selfVerificationLoadHalfword(InterpState* interpState)
162{
163 Thread *self = dvmThreadSelf();
164 ShadowHeap *heapSpacePtr;
165 ShadowSpace *shadowSpace = self->shadowSpace;
166 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
167
168 int addr, data;
169 selfVerificationLoadDecode(heapArgSpace, &addr);
170
171 int maskedAddr = addr & 0xFFFFFFFC;
172 int alignment = addr & 0x2;
173
174 for (heapSpacePtr = shadowSpace->heapSpace;
175 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
176 if (heapSpacePtr->addr == maskedAddr) {
177 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
178 data = *((unsigned short*) addr);
179 break;
180 }
181 }
182
183 if (heapSpacePtr == shadowSpace->heapSpaceTail)
184 data = *((unsigned short*) addr);
185
186 //LOGD("*** HEAP LOAD HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
187
188 int reg = (heapArgSpace->regMap >> 4) & 0xF;
189 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
190}
191
192static void selfVerificationLoadSignedByte(InterpState* interpState)
193{
194 Thread *self = dvmThreadSelf();
195 ShadowHeap* heapSpacePtr;
196 ShadowSpace* shadowSpace = self->shadowSpace;
197 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
198
199 int addr, data;
200 selfVerificationLoadDecode(heapArgSpace, &addr);
201
202 int maskedAddr = addr & 0xFFFFFFFC;
203 int alignment = addr & 0x3;
204
205 for (heapSpacePtr = shadowSpace->heapSpace;
206 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
207 if (heapSpacePtr->addr == maskedAddr) {
208 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
209 data = *((signed char*) addr);
210 break;
211 }
212 }
213
214 if (heapSpacePtr == shadowSpace->heapSpaceTail)
215 data = *((signed char*) addr);
216
217 //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
218
219 int reg = (heapArgSpace->regMap >> 4) & 0xF;
220 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
221}
222
223static void selfVerificationLoadSignedHalfword(InterpState* interpState)
224{
225 Thread *self = dvmThreadSelf();
226 ShadowHeap* heapSpacePtr;
227 ShadowSpace* shadowSpace = self->shadowSpace;
228 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
229
230 int addr, data;
231 selfVerificationLoadDecode(heapArgSpace, &addr);
232
233 int maskedAddr = addr & 0xFFFFFFFC;
234 int alignment = addr & 0x2;
235
236 for (heapSpacePtr = shadowSpace->heapSpace;
237 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
238 if (heapSpacePtr->addr == maskedAddr) {
239 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
240 data = *((signed short*) addr);
241 break;
242 }
243 }
244
245 if (heapSpacePtr == shadowSpace->heapSpaceTail)
246 data = *((signed short*) addr);
247
248 //LOGD("*** HEAP LOAD SIGNED HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
249
250 int reg = (heapArgSpace->regMap >> 4) & 0xF;
251 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
252}
253
254static void selfVerificationLoadDoubleword(InterpState* interpState)
255{
256 Thread *self = dvmThreadSelf();
257 ShadowHeap* heapSpacePtr;
258 ShadowSpace* shadowSpace = self->shadowSpace;
259 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
260
261 int addr;
262 selfVerificationLoadDecode(heapArgSpace, &addr);
263
264 int addr2 = addr+4;
265 unsigned int data = *((unsigned int*) addr);
266 unsigned int data2 = *((unsigned int*) addr2);
267
268 for (heapSpacePtr = shadowSpace->heapSpace;
269 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
270 if (heapSpacePtr->addr == addr) {
271 data = heapSpacePtr->data;
272 } else if (heapSpacePtr->addr == addr2) {
273 data2 = heapSpacePtr->data;
274 }
275 }
276
277 //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
278 // addr, data, data2);
279
280 int reg = (heapArgSpace->regMap >> 4) & 0xF;
281 int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
282 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
283 selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
284}
285
286/* Decode contents of heapArgSpace to determine arguments to store. */
287static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
288 int* value, int reg)
289{
290 switch (reg) {
291 case 0:
292 *value = heapArgSpace->r0;
293 break;
294 case 1:
295 *value = heapArgSpace->r1;
296 break;
297 case 2:
298 *value = heapArgSpace->r2;
299 break;
300 case 3:
301 *value = heapArgSpace->r3;
302 break;
303 default:
304 LOGE("ERROR: bad reg passed to selfVerificationStoreDecode: %d",
305 reg);
306 break;
307 }
308}
309
310static void selfVerificationStore(InterpState* interpState)
311{
312 Thread *self = dvmThreadSelf();
313 ShadowHeap *heapSpacePtr;
314 ShadowSpace *shadowSpace = self->shadowSpace;
315 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
316
317 int addr, data;
318 int reg0 = heapArgSpace->regMap & 0xF;
319 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
320 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
321 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
322
323 //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
324
325 for (heapSpacePtr = shadowSpace->heapSpace;
326 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
327 if (heapSpacePtr->addr == addr) break;
328 }
329
330 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
331 heapSpacePtr->addr = addr;
332 shadowSpace->heapSpaceTail++;
333 }
334
335 heapSpacePtr->data = data;
336}
337
338static void selfVerificationStoreByte(InterpState* interpState)
339{
340 Thread *self = dvmThreadSelf();
341 ShadowHeap *heapSpacePtr;
342 ShadowSpace *shadowSpace = self->shadowSpace;
343 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
344
345 int addr, data;
346 int reg0 = heapArgSpace->regMap & 0xF;
347 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
348 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
349 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
350
351 int maskedAddr = addr & 0xFFFFFFFC;
352 int alignment = addr & 0x3;
353
354 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
355
356 for (heapSpacePtr = shadowSpace->heapSpace;
357 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
358 if (heapSpacePtr->addr == maskedAddr) break;
359 }
360
361 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
362 heapSpacePtr->addr = maskedAddr;
363 heapSpacePtr->data = *((unsigned int*) maskedAddr);
364 shadowSpace->heapSpaceTail++;
365 }
366
367 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
368 *((unsigned char*) addr) = (char) data;
369
370 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
371 // addr, heapSpacePtr->data);
372}
373
374static void selfVerificationStoreHalfword(InterpState* interpState)
375{
376 Thread *self = dvmThreadSelf();
377 ShadowHeap *heapSpacePtr;
378 ShadowSpace *shadowSpace = self->shadowSpace;
379 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
380
381 int addr, data;
382 int reg0 = heapArgSpace->regMap & 0xF;
383 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
384 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
385 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
386
387 int maskedAddr = addr & 0xFFFFFFFC;
388 int alignment = addr & 0x2;
389
390 //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Data: 0x%x", addr, data);
391
392 for (heapSpacePtr = shadowSpace->heapSpace;
393 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
394 if (heapSpacePtr->addr == maskedAddr) break;
395 }
396
397 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
398 heapSpacePtr->addr = maskedAddr;
399 heapSpacePtr->data = *((unsigned int*) maskedAddr);
400 shadowSpace->heapSpaceTail++;
401 }
402
403 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
404 *((unsigned short*) addr) = (short) data;
405
406 //LOGD("*** HEAP STORE HALFWORD: Addr: 0x%x Final Data: 0x%x",
407 // addr, heapSpacePtr->data);
408}
409
410static void selfVerificationStoreDoubleword(InterpState* interpState)
411{
412 Thread *self = dvmThreadSelf();
413 ShadowHeap *heapSpacePtr;
414 ShadowSpace *shadowSpace = self->shadowSpace;
415 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
416
417 int addr, data, data2;
418 int reg0 = heapArgSpace->regMap & 0xF;
419 int reg1 = (heapArgSpace->regMap >> 4) & 0xF;
420 int reg2 = (heapArgSpace->regMap >> 8) & 0xF;
421 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
422 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
423 selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
424
425 int addr2 = addr+4;
426 bool store1 = false, store2 = false;
427
428 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
429 // addr, data, data2);
430
431 for (heapSpacePtr = shadowSpace->heapSpace;
432 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
433 if (heapSpacePtr->addr == addr) {
434 heapSpacePtr->data = data;
435 store1 = true;
436 } else if (heapSpacePtr->addr == addr2) {
437 heapSpacePtr->data = data2;
438 store2 = true;
439 }
440 }
441
442 if (!store1) {
443 shadowSpace->heapSpaceTail->addr = addr;
444 shadowSpace->heapSpaceTail->data = data;
445 shadowSpace->heapSpaceTail++;
446 }
447 if (!store2) {
448 shadowSpace->heapSpaceTail->addr = addr2;
449 shadowSpace->heapSpaceTail->data = data2;
450 shadowSpace->heapSpaceTail++;
451 }
452}
453
454/* Common wrapper function for all memory operations */
455static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
456 void* funct)
457{
458 int regMask = (1 << r4PC) | (1 << r3) | (1 << r2) | (1 << r1) | (1 << r0);
459
460 /* r7 <- InterpState->heapArgSpace */
461 loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
462 newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
463
464 /* Save out values to heapArgSpace */
465 loadConstant(cUnit, r4PC, regMap);
466 newLIR2(cUnit, THUMB_STMIA, r7, regMask);
467
468 /* Pass interpState pointer to function */
469 newLIR2(cUnit, THUMB_MOV_RR, r0, rGLUE);
470
471 /* Set function pointer and branch */
472 loadConstant(cUnit, r1, (int) funct);
473 newLIR1(cUnit, THUMB_BLX_R, r1);
474
475 /* r7 <- InterpState->heapArgSpace */
476 loadConstant(cUnit, r4PC, offsetof(InterpState, heapArgSpace));
477 newLIR3(cUnit, THUMB_ADD_RRR, r7, rGLUE, r4PC);
478
479 /* Restore register state */
480 newLIR2(cUnit, THUMB_LDMIA, r7, regMask);
481}
482#endif
483
Ben Chengba4fc8b2009-06-01 13:00:29 -0700484/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700485 * The following are building blocks to construct low-level IRs with 0 - 4
Ben Chengba4fc8b2009-06-01 13:00:29 -0700486 * operands.
487 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700488static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700489{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700490 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700491 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700492 insn->opCode = opCode;
493 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
494 return insn;
495}
496
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700497static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700498 int dest)
499{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700500 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700501 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700502 insn->opCode = opCode;
503 insn->operands[0] = dest;
504 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
505 return insn;
506}
507
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700508static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700509 int dest, int src1)
510{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700511 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700512 assert(isPseudoOpCode(opCode) ||
513 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700514 insn->opCode = opCode;
515 insn->operands[0] = dest;
516 insn->operands[1] = src1;
517 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
518 return insn;
519}
520
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700521static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700522 int dest, int src1, int src2)
523{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700524 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700525 assert(isPseudoOpCode(opCode) ||
526 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700527 insn->opCode = opCode;
528 insn->operands[0] = dest;
529 insn->operands[1] = src1;
530 insn->operands[2] = src2;
531 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
532 return insn;
533}
534
Bill Buzbee270c1d62009-08-13 16:58:07 -0700535static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
536 int dest, int src1, int src2, int info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700537{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700538 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
539 assert(isPseudoOpCode(opCode) ||
540 (EncodingMap[opCode].flags & IS_QUAD_OP));
541 insn->opCode = opCode;
542 insn->operands[0] = dest;
543 insn->operands[1] = src1;
544 insn->operands[2] = src2;
545 insn->operands[3] = info;
546 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
547 return insn;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700548}
549
Ben Chengba4fc8b2009-06-01 13:00:29 -0700550/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700551 * If the next instruction is a move-result or move-result-long,
552 * return the target Dalvik instruction and convert the next to a
553 * nop. Otherwise, return -1. Used to optimize method inlining.
554 */
555static int inlinedTarget(MIR *mir)
556{
557 if (mir->next &&
558 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
559 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT) ||
560 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE))) {
561 mir->next->dalvikInsn.opCode = OP_NOP;
562 return mir->next->dalvikInsn.vA;
563 } else {
564 return -1;
565 }
566}
567
568
569
570/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700571 * The following are building blocks to insert constants into the pool or
572 * instruction streams.
573 */
574
575/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700576static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700577{
578 /* Add the constant to the literal pool */
579 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700580 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700581 newValue->operands[0] = value;
582 newValue->generic.next = cUnit->wordList;
583 cUnit->wordList = (LIR *) newValue;
584 return newValue;
585 } else {
586 /* Add the constant in the middle of code stream */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700587 newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
588 newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700589 }
590 return NULL;
591}
592
593/*
594 * Search the existing constants in the literal pool for an exact or close match
595 * within specified delta (greater or equal to 0).
596 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700597static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700598 unsigned int delta)
599{
600 LIR *dataTarget = cUnit->wordList;
601 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700602 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700603 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700604 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700605 dataTarget = dataTarget->next;
606 }
607 return NULL;
608}
609
Ben Chengba4fc8b2009-06-01 13:00:29 -0700610/* Perform the actual operation for OP_RETURN_* */
611static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
612{
613 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
614#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700615 gDvmJit.returnOp++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700616#endif
617 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700618 /* Insert branch, but defer setting of target */
619 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700620 /* Set up the place holder to reconstruct this Dalvik PC */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700621 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
622 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700623 pcrLabel->operands[0] = dPC;
624 pcrLabel->operands[1] = mir->offset;
625 /* Insert the place holder to the growable list */
626 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
627 /* Branch to the PC reconstruction code */
628 branch->generic.target = (LIR *) pcrLabel;
629}
630
Ben Chengba4fc8b2009-06-01 13:00:29 -0700631/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700632static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
633 ArmLIR *branch,
634 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700635{
636 /* Set up the place holder to reconstruct this Dalvik PC */
637 if (pcrLabel == NULL) {
638 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700639 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
640 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700641 pcrLabel->operands[0] = dPC;
642 pcrLabel->operands[1] = dOffset;
643 /* Insert the place holder to the growable list */
644 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
645 }
646 /* Branch to the PC reconstruction code */
647 branch->generic.target = (LIR *) pcrLabel;
648 return pcrLabel;
649}
650
Ben Chengba4fc8b2009-06-01 13:00:29 -0700651
652/*
653 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
654 * satisfies.
655 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700656static inline ArmLIR *insertRegRegCheck(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700657 ArmConditionCode cond,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700658 int reg1, int reg2, int dOffset,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700659 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700660{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700661 ArmLIR *res;
662 res = opRegReg(cUnit, OP_CMP, reg1, reg2);
663 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
664 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
665 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700666}
667
Ben Chenge9695e52009-06-16 16:11:47 -0700668/*
669 * Perform null-check on a register. vReg is the Dalvik register being checked,
670 * and mReg is the machine register holding the actual value. If internal state
671 * indicates that vReg has been checked before the check request is ignored.
672 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700673static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
674 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700675{
Ben Chenge9695e52009-06-16 16:11:47 -0700676 /* This particular Dalvik register has been null-checked */
677 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
678 return pcrLabel;
679 }
680 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
681 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
682}
683
684/*
685 * Perform zero-check on a register. Similar to genNullCheck but the value being
686 * checked does not have a corresponding Dalvik register.
687 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700688static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
689 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -0700690{
691 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700692}
693
694/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700695static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
696 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700697{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700698 return insertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700699 pcrLabel);
700}
701
702/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700703static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
704 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700705{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700706 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700707 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
708}
709
710/* Load a wide field from an object instance */
711static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
712{
713 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700714 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700715
Ben Chenge9695e52009-06-16 16:11:47 -0700716 /* Allocate reg0..reg3 into physical registers r0..r3 */
717
718 /* See if vB is in a native register. If so, reuse it. */
719 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
720 /* Ping reg3 to the other register of the same pair containing reg2 */
721 reg3 = reg2 ^ 0x1;
722 /*
723 * Ping reg0 to the first register of the alternate register pair
724 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700725 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700726 reg1 = NEXT_REG(reg0);
727
728 loadValue(cUnit, dInsn->vB, reg2);
729 loadConstant(cUnit, reg3, fieldOffset);
730 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700731 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700732#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700733 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700734#else
735 int regMap = reg1 << 8 | reg0 << 4 | reg2;
736 selfVerificationMemOpWrapper(cUnit, regMap,
737 &selfVerificationLoadDoubleword);
Jeff Hao97319a82009-08-12 16:57:15 -0700738#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700739 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700740}
741
742/* Store a wide field to an object instance */
743static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
744{
745 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700746 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700747
Ben Chenge9695e52009-06-16 16:11:47 -0700748 /* Allocate reg0..reg3 into physical registers r0..r3 */
749
750 /* See if vB is in a native register. If so, reuse it. */
751 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
752 /* Ping reg3 to the other register of the same pair containing reg2 */
753 reg3 = reg2 ^ 0x1;
754 /*
755 * Ping reg0 to the first register of the alternate register pair
756 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700757 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700758 reg1 = NEXT_REG(reg0);
759
760
761 loadValue(cUnit, dInsn->vB, reg2);
762 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
763 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
764 loadConstant(cUnit, reg3, fieldOffset);
765 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700766 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700767#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700768 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700769#else
770 int regMap = reg1 << 8 | reg0 << 4 | reg2;
771 selfVerificationMemOpWrapper(cUnit, regMap,
772 &selfVerificationStoreDoubleword);
773#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700774}
775
776/*
777 * Load a field from an object instance
778 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700779 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700780static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700781 int fieldOffset)
782{
783 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700784 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700785
Ben Chenge9695e52009-06-16 16:11:47 -0700786 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
787 reg1 = NEXT_REG(reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700788 loadValue(cUnit, dInsn->vB, reg0);
Jeff Hao97319a82009-08-12 16:57:15 -0700789#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700790 loadBaseDisp(cUnit, mir, reg0, fieldOffset, reg1, size, true, dInsn->vB);
Jeff Hao97319a82009-08-12 16:57:15 -0700791#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700792 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700793 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700794 loadConstant(cUnit, reg1, fieldOffset);
795 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700796
Bill Buzbee270c1d62009-08-13 16:58:07 -0700797 int regMap = reg1 << 4 | reg0;
Jeff Hao97319a82009-08-12 16:57:15 -0700798 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
Jeff Hao97319a82009-08-12 16:57:15 -0700799#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700800 storeValue(cUnit, reg1, dInsn->vA, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700801}
802
803/*
804 * Store a field to an object instance
805 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700806 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700807static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700808 int fieldOffset)
809{
810 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700811 int reg0, reg1, reg2;
812
813 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
814 reg1 = NEXT_REG(reg0);
815 reg2 = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700816
Ben Chenge9695e52009-06-16 16:11:47 -0700817 loadValue(cUnit, dInsn->vB, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700818 loadValue(cUnit, dInsn->vA, reg2);
819 updateLiveRegister(cUnit, dInsn->vA, reg2);
820 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700821#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700822 storeBaseDisp(cUnit, reg0, fieldOffset, reg2, size, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700823#else
824 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700825 loadConstant(cUnit, reg1, fieldOffset);
826 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700827
828 int regMap = reg2 << 4 | reg0;
829 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
830
Bill Buzbee270c1d62009-08-13 16:58:07 -0700831 opRegReg(cUnit, OP_SUB, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700832#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700833}
834
835
Ben Chengba4fc8b2009-06-01 13:00:29 -0700836/*
837 * Generate array load
838 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700839 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700840static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700841 int vArray, int vIndex, int vDest, int scale)
842{
843 int lenOffset = offsetof(ArrayObject, length);
844 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700845 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700846
Ben Chenge9695e52009-06-16 16:11:47 -0700847 reg0 = selectFirstRegister(cUnit, vArray, false);
848 reg1 = NEXT_REG(reg0);
849 reg2 = NEXT_REG(reg1);
850 reg3 = NEXT_REG(reg2);
851
852 loadValue(cUnit, vArray, reg2);
853 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700854
855 /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700856 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
857 loadWordDisp(cUnit, reg2, lenOffset, reg0); /* Get len */
858 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone); /* reg2 -> array data */
Ben Chenge9695e52009-06-16 16:11:47 -0700859 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
Jeff Hao97319a82009-08-12 16:57:15 -0700860#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700861 if ((size == LONG) || (size == DOUBLE)) {
862 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
863 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
864 loadBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
865 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
866 loadBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
Ben Chenge9695e52009-06-16 16:11:47 -0700867 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700868 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700869 loadBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
Ben Chenge9695e52009-06-16 16:11:47 -0700870 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700871 }
Jeff Hao97319a82009-08-12 16:57:15 -0700872#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700873 //TODO: probably want to move this into loadBaseIndexed
874 void *funct = NULL;
875 switch(size) {
876 case LONG:
877 case DOUBLE:
Jeff Hao97319a82009-08-12 16:57:15 -0700878 funct = (void*) &selfVerificationLoadDoubleword;
879 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700880 case WORD:
Jeff Hao97319a82009-08-12 16:57:15 -0700881 funct = (void*) &selfVerificationLoad;
882 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700883 case UNSIGNED_HALF:
884 funct = (void*) &selfVerificationLoadHalfword;
885 break;
886 case SIGNED_HALF:
887 funct = (void*) &selfVerificationLoadSignedHalfword;
888 break;
889 case UNSIGNED_BYTE:
890 funct = (void*) &selfVerificationLoadByte;
891 break;
892 case SIGNED_BYTE:
893 funct = (void*) &selfVerificationLoadSignedByte;
894 break;
895 default:
896 assert(0);
897 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -0700898 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700899 /* Combine address and index */
900 if (scale)
901 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
902 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700903
904 int regMap = reg1 << 8 | reg0 << 4 | reg2;
905 selfVerificationMemOpWrapper(cUnit, regMap, funct);
906
Bill Buzbee270c1d62009-08-13 16:58:07 -0700907 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700908
Bill Buzbee270c1d62009-08-13 16:58:07 -0700909 if ((size == LONG) || (size == DOUBLE))
Jeff Hao97319a82009-08-12 16:57:15 -0700910 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
911 else
912 storeValue(cUnit, reg0, vDest, reg3);
913#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700914}
915
Ben Chengba4fc8b2009-06-01 13:00:29 -0700916/*
917 * Generate array store
918 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700919 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700920static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700921 int vArray, int vIndex, int vSrc, int scale)
922{
923 int lenOffset = offsetof(ArrayObject, length);
924 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700925 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700926
Ben Chenge9695e52009-06-16 16:11:47 -0700927 reg0 = selectFirstRegister(cUnit, vArray, false);
928 reg1 = NEXT_REG(reg0);
929 reg2 = NEXT_REG(reg1);
930 reg3 = NEXT_REG(reg2);
931
932 loadValue(cUnit, vArray, reg2);
933 loadValue(cUnit, vIndex, reg3);
934
Ben Cheng1efc9c52009-06-08 18:25:27 -0700935 /* null object? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700936 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
Ben Chenge9695e52009-06-16 16:11:47 -0700937 NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700938 loadWordDisp(cUnit, reg2, lenOffset, reg0); /* Get len */
939 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone); /* reg2 -> array data */
Ben Chenge9695e52009-06-16 16:11:47 -0700940 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
941 /* at this point, reg2 points to array, reg3 is unscaled index */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700942#if !defined(WITH_SELF_VERIFICATION)
943 if ((size == LONG) || (size == DOUBLE)) {
944 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
945 loadValuePair(cUnit, vSrc, reg0, reg1);
946 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
947 if (scale)
948 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
949 storeBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
950 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
951 storeBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
952 } else {
953 loadValue(cUnit, vSrc, reg0);
954 updateLiveRegister(cUnit, vSrc, reg0);
955 storeBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
956 }
957#else
958 //TODO: probably want to move this into storeBaseIndexed
959 void *funct = NULL;
960 switch(size) {
961 case LONG:
962 case DOUBLE:
963 funct = (void*) &selfVerificationStoreDoubleword;
964 break;
965 case WORD:
966 funct = (void*) &selfVerificationStore;
967 break;
968 case SIGNED_HALF:
969 case UNSIGNED_HALF:
970 funct = (void*) &selfVerificationStoreHalfword;
971 break;
972 case SIGNED_BYTE:
973 case UNSIGNED_BYTE:
974 funct = (void*) &selfVerificationStoreByte;
975 break;
976 default:
977 assert(0);
978 dvmAbort();
979 }
980
981 /* Combine address and index */
982 if ((size == LONG) || (size == DOUBLE)) {
Ben Chenge9695e52009-06-16 16:11:47 -0700983 loadValuePair(cUnit, vSrc, reg0, reg1);
984 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700985 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700986 loadValue(cUnit, vSrc, reg0);
987 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700988 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700989 if (scale)
990 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
991 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700992
993 int regMap = reg1 << 8 | reg0 << 4 | reg2;
994 selfVerificationMemOpWrapper(cUnit, regMap, funct);
995
Bill Buzbee270c1d62009-08-13 16:58:07 -0700996 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700997#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700998}
999
1000static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1001 int vSrc1, int vShift)
1002{
Ben Chenge9695e52009-06-16 16:11:47 -07001003 /*
1004 * Don't mess with the regsiters here as there is a particular calling
1005 * convention to the out-of-line handler.
1006 */
1007 loadValue(cUnit, vShift, r2);
1008 loadValuePair(cUnit, vSrc1, r0, r1);
1009 switch( mir->dalvikInsn.opCode) {
1010 case OP_SHL_LONG:
1011 case OP_SHL_LONG_2ADDR:
1012 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1013 break;
1014 case OP_SHR_LONG:
1015 case OP_SHR_LONG_2ADDR:
1016 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1017 break;
1018 case OP_USHR_LONG:
1019 case OP_USHR_LONG_2ADDR:
1020 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1021 break;
1022 default:
1023 return true;
1024 }
1025 storeValuePair(cUnit, r0, r1, vDest, r2);
1026 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001027}
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001028bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1029 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001030{
Ben Chenge9695e52009-06-16 16:11:47 -07001031 /*
1032 * Don't optimize the regsiter usage here as they are governed by the EABI
1033 * calling convention.
1034 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001035 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001036 int reg0, reg1;
1037
Ben Chengba4fc8b2009-06-01 13:00:29 -07001038 /* TODO: use a proper include file to define these */
1039 float __aeabi_fadd(float a, float b);
1040 float __aeabi_fsub(float a, float b);
1041 float __aeabi_fdiv(float a, float b);
1042 float __aeabi_fmul(float a, float b);
1043 float fmodf(float a, float b);
1044
Ben Chenge9695e52009-06-16 16:11:47 -07001045 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1046 reg1 = NEXT_REG(reg0);
1047
Ben Chengba4fc8b2009-06-01 13:00:29 -07001048 switch (mir->dalvikInsn.opCode) {
1049 case OP_ADD_FLOAT_2ADDR:
1050 case OP_ADD_FLOAT:
1051 funct = (void*) __aeabi_fadd;
1052 break;
1053 case OP_SUB_FLOAT_2ADDR:
1054 case OP_SUB_FLOAT:
1055 funct = (void*) __aeabi_fsub;
1056 break;
1057 case OP_DIV_FLOAT_2ADDR:
1058 case OP_DIV_FLOAT:
1059 funct = (void*) __aeabi_fdiv;
1060 break;
1061 case OP_MUL_FLOAT_2ADDR:
1062 case OP_MUL_FLOAT:
1063 funct = (void*) __aeabi_fmul;
1064 break;
1065 case OP_REM_FLOAT_2ADDR:
1066 case OP_REM_FLOAT:
1067 funct = (void*) fmodf;
1068 break;
1069 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -07001070 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001071 opRegImm(cUnit, OP_ADD, reg0, 0x80000000, reg1);
Ben Chenge9695e52009-06-16 16:11:47 -07001072 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001073 return false;
1074 }
1075 default:
1076 return true;
1077 }
1078 loadConstant(cUnit, r2, (int)funct);
1079 loadValue(cUnit, vSrc1, r0);
1080 loadValue(cUnit, vSrc2, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001081 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001082 storeValue(cUnit, r0, vDest, r1);
1083 return false;
1084}
1085
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001086bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1087 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001088{
1089 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001090 int reg0, reg1, reg2;
1091
Ben Chengba4fc8b2009-06-01 13:00:29 -07001092 /* TODO: use a proper include file to define these */
1093 double __aeabi_dadd(double a, double b);
1094 double __aeabi_dsub(double a, double b);
1095 double __aeabi_ddiv(double a, double b);
1096 double __aeabi_dmul(double a, double b);
1097 double fmod(double a, double b);
1098
Ben Chenge9695e52009-06-16 16:11:47 -07001099 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1100 reg1 = NEXT_REG(reg0);
1101 reg2 = NEXT_REG(reg1);
1102
Ben Chengba4fc8b2009-06-01 13:00:29 -07001103 switch (mir->dalvikInsn.opCode) {
1104 case OP_ADD_DOUBLE_2ADDR:
1105 case OP_ADD_DOUBLE:
1106 funct = (void*) __aeabi_dadd;
1107 break;
1108 case OP_SUB_DOUBLE_2ADDR:
1109 case OP_SUB_DOUBLE:
1110 funct = (void*) __aeabi_dsub;
1111 break;
1112 case OP_DIV_DOUBLE_2ADDR:
1113 case OP_DIV_DOUBLE:
1114 funct = (void*) __aeabi_ddiv;
1115 break;
1116 case OP_MUL_DOUBLE_2ADDR:
1117 case OP_MUL_DOUBLE:
1118 funct = (void*) __aeabi_dmul;
1119 break;
1120 case OP_REM_DOUBLE_2ADDR:
1121 case OP_REM_DOUBLE:
1122 funct = (void*) fmod;
1123 break;
1124 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001125 loadValuePair(cUnit, vSrc2, reg0, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001126 opRegImm(cUnit, OP_ADD, reg1, 0x80000000, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001127 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001128 return false;
1129 }
1130 default:
1131 return true;
1132 }
Ben Chenge9695e52009-06-16 16:11:47 -07001133 /*
1134 * Don't optimize the regsiter usage here as they are governed by the EABI
1135 * calling convention.
1136 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001137 loadConstant(cUnit, r4PC, (int)funct);
1138 loadValuePair(cUnit, vSrc1, r0, r1);
1139 loadValuePair(cUnit, vSrc2, r2, r3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001140 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001141 storeValuePair(cUnit, r0, r1, vDest, r2);
1142 return false;
1143}
1144
1145static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1146 int vSrc1, int vSrc2)
1147{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001148 OpKind firstOp = OP_BKPT;
1149 OpKind secondOp = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001150 bool callOut = false;
1151 void *callTgt;
1152 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -07001153 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001154 /* TODO - find proper .h file to declare these */
1155 long long __aeabi_ldivmod(long long op1, long long op2);
1156
1157 switch (mir->dalvikInsn.opCode) {
1158 case OP_NOT_LONG:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001159 firstOp = OP_MVN;
1160 secondOp = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001161 break;
1162 case OP_ADD_LONG:
1163 case OP_ADD_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001164 firstOp = OP_ADD;
1165 secondOp = OP_ADC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001166 break;
1167 case OP_SUB_LONG:
1168 case OP_SUB_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001169 firstOp = OP_SUB;
1170 secondOp = OP_SBC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001171 break;
1172 case OP_MUL_LONG:
1173 case OP_MUL_LONG_2ADDR:
1174 loadValuePair(cUnit, vSrc1, r0, r1);
1175 loadValuePair(cUnit, vSrc2, r2, r3);
1176 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
1177 storeValuePair(cUnit, r0, r1, vDest, r2);
1178 return false;
1179 break;
1180 case OP_DIV_LONG:
1181 case OP_DIV_LONG_2ADDR:
1182 callOut = true;
1183 retReg = r0;
1184 callTgt = (void*)__aeabi_ldivmod;
1185 break;
1186 /* NOTE - result is in r2/r3 instead of r0/r1 */
1187 case OP_REM_LONG:
1188 case OP_REM_LONG_2ADDR:
1189 callOut = true;
1190 callTgt = (void*)__aeabi_ldivmod;
1191 retReg = r2;
1192 break;
1193 case OP_AND_LONG:
1194 case OP_AND_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001195 firstOp = OP_AND;
1196 secondOp = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001197 break;
1198 case OP_OR_LONG:
1199 case OP_OR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001200 firstOp = OP_OR;
1201 secondOp = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001202 break;
1203 case OP_XOR_LONG:
1204 case OP_XOR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001205 firstOp = OP_XOR;
1206 secondOp = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001207 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001208 case OP_NEG_LONG: {
1209 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1210 reg1 = NEXT_REG(reg0);
1211 reg2 = NEXT_REG(reg1);
1212 reg3 = NEXT_REG(reg2);
1213
1214 loadValuePair(cUnit, vSrc2, reg0, reg1);
1215 loadConstant(cUnit, reg3, 0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001216 opRegRegReg(cUnit, OP_SUB, reg2, reg3, reg0);
1217 opRegReg(cUnit, OP_SBC, reg3, reg1);
Ben Cheng38329f52009-07-07 14:19:20 -07001218 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001219 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001220 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001221 default:
1222 LOGE("Invalid long arith op");
1223 dvmAbort();
1224 }
1225 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001226 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1227 reg1 = NEXT_REG(reg0);
1228 reg2 = NEXT_REG(reg1);
1229 reg3 = NEXT_REG(reg2);
1230
1231 loadValuePair(cUnit, vSrc1, reg0, reg1);
1232 loadValuePair(cUnit, vSrc2, reg2, reg3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001233 opRegReg(cUnit, firstOp, reg0, reg2);
1234 opRegReg(cUnit, secondOp, reg1, reg3);
1235 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001236 /*
Bill Buzbee270c1d62009-08-13 16:58:07 -07001237 * Don't optimize the register usage here as they are governed by the EABI
Ben Chenge9695e52009-06-16 16:11:47 -07001238 * calling convention.
1239 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001240 } else {
1241 loadValuePair(cUnit, vSrc2, r2, r3);
1242 loadConstant(cUnit, r4PC, (int) callTgt);
1243 loadValuePair(cUnit, vSrc1, r0, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001244 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001245 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1246 }
1247 return false;
1248}
1249
1250static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1251 int vSrc1, int vSrc2)
1252{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001253 OpKind op = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001254 bool callOut = false;
1255 bool checkZero = false;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001256 bool threeOperand = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001257 int retReg = r0;
1258 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -07001259 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001260
1261 /* TODO - find proper .h file to declare these */
1262 int __aeabi_idivmod(int op1, int op2);
1263 int __aeabi_idiv(int op1, int op2);
1264
1265 switch (mir->dalvikInsn.opCode) {
1266 case OP_NEG_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001267 op = OP_NEG;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001268 break;
1269 case OP_NOT_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001270 op = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001271 break;
1272 case OP_ADD_INT:
1273 case OP_ADD_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001274 op = OP_ADD;
1275 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001276 break;
1277 case OP_SUB_INT:
1278 case OP_SUB_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001279 op = OP_SUB;
1280 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001281 break;
1282 case OP_MUL_INT:
1283 case OP_MUL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001284 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001285 break;
1286 case OP_DIV_INT:
1287 case OP_DIV_INT_2ADDR:
1288 callOut = true;
1289 checkZero = true;
1290 callTgt = __aeabi_idiv;
1291 retReg = r0;
1292 break;
1293 /* NOTE: returns in r1 */
1294 case OP_REM_INT:
1295 case OP_REM_INT_2ADDR:
1296 callOut = true;
1297 checkZero = true;
1298 callTgt = __aeabi_idivmod;
1299 retReg = r1;
1300 break;
1301 case OP_AND_INT:
1302 case OP_AND_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001303 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001304 break;
1305 case OP_OR_INT:
1306 case OP_OR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001307 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001308 break;
1309 case OP_XOR_INT:
1310 case OP_XOR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001311 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001312 break;
1313 case OP_SHL_INT:
1314 case OP_SHL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001315 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001316 break;
1317 case OP_SHR_INT:
1318 case OP_SHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001319 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001320 break;
1321 case OP_USHR_INT:
1322 case OP_USHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001323 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001324 break;
1325 default:
1326 LOGE("Invalid word arith op: 0x%x(%d)",
1327 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1328 dvmAbort();
1329 }
1330 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001331 /* Try to allocate reg0 to the currently cached source operand */
1332 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1333 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1334 reg1 = NEXT_REG(reg0);
1335 regDest = NEXT_REG(reg1);
1336
1337 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1338 loadValue(cUnit, vSrc2, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001339 if (threeOperand) {
1340 opRegRegReg(cUnit, op, regDest, reg0, reg1);
1341 storeValue(cUnit, regDest, vDest, reg1);
1342 } else {
1343 opRegReg(cUnit, op, reg0, reg1);
1344 storeValue(cUnit, reg0, vDest, reg1);
1345 }
Ben Chenge9695e52009-06-16 16:11:47 -07001346 } else {
1347 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1348 reg1 = NEXT_REG(reg0);
1349 regDest = NEXT_REG(reg1);
1350
1351 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1352 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001353 if (threeOperand) {
1354 opRegRegReg(cUnit, op, regDest, reg1, reg0);
1355 storeValue(cUnit, regDest, vDest, reg1);
1356 } else {
1357 opRegReg(cUnit, op, reg1, reg0);
1358 storeValue(cUnit, reg1, vDest, reg0);
1359 }
Ben Chenge9695e52009-06-16 16:11:47 -07001360 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001361 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001362 /*
1363 * Load the callout target first since it will never be eliminated
1364 * and its value will be used first.
1365 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001366 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -07001367 /*
1368 * Load vSrc2 first if it is not cached in a native register or it
1369 * is in r0 which will be clobbered if vSrc1 is loaded first.
1370 */
1371 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1372 cUnit->registerScoreboard.nativeReg == r0) {
1373 /* Cannot be optimized and won't clobber r0 */
1374 loadValue(cUnit, vSrc2, r1);
1375 /* May be optimized if vSrc1 is cached */
1376 loadValue(cUnit, vSrc1, r0);
1377 } else {
1378 loadValue(cUnit, vSrc1, r0);
1379 loadValue(cUnit, vSrc2, r1);
1380 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001381 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -07001382 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001383 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001384 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001385 storeValue(cUnit, retReg, vDest, r2);
1386 }
1387 return false;
1388}
1389
1390static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1391{
1392 OpCode opCode = mir->dalvikInsn.opCode;
1393 int vA = mir->dalvikInsn.vA;
1394 int vB = mir->dalvikInsn.vB;
1395 int vC = mir->dalvikInsn.vC;
1396
1397 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1398 return genArithOpLong(cUnit,mir, vA, vA, vB);
1399 }
1400 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1401 return genArithOpLong(cUnit,mir, vA, vB, vC);
1402 }
1403 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1404 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1405 }
1406 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1407 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1408 }
1409 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1410 return genArithOpInt(cUnit,mir, vA, vA, vB);
1411 }
1412 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1413 return genArithOpInt(cUnit,mir, vA, vB, vC);
1414 }
1415 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001416 return genArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001417 }
1418 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001419 return genArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001420 }
1421 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001422 return genArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001423 }
1424 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001425 return genArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001426 }
1427 return true;
1428}
1429
Bill Buzbeed45ba372009-06-15 17:00:57 -07001430static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1431 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001432{
Ben Chenge9695e52009-06-16 16:11:47 -07001433 /*
1434 * Don't optimize the register usage since it calls out to template
1435 * functions
1436 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001437 loadConstant(cUnit, r2, (int)funct);
1438 if (srcSize == 1) {
1439 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1440 } else {
1441 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1442 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001443 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001444 if (tgtSize == 1) {
1445 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1446 } else {
1447 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1448 }
1449 return false;
1450}
1451
Ben Chengba4fc8b2009-06-01 13:00:29 -07001452static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1453 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001454 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001455{
1456 unsigned int i;
1457 unsigned int regMask = 0;
1458
1459 /* Load arguments to r0..r4 */
1460 for (i = 0; i < dInsn->vA; i++) {
1461 regMask |= 1 << i;
1462 loadValue(cUnit, dInsn->arg[i], i);
1463 }
1464 if (regMask) {
1465 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001466 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1467 sizeof(StackSaveArea) + (dInsn->vA << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001468 /* generate null check */
1469 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001470 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1471 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001472 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001473 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001474 }
1475}
1476
1477static void genProcessArgsRange(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 int srcOffset = dInsn->vC << 2;
1482 int numArgs = dInsn->vA;
1483 int regMask;
1484 /*
1485 * r4PC : &rFP[vC]
1486 * r7: &newFP[0]
1487 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001488 opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001489 /* load [r0 .. min(numArgs,4)] */
1490 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001491 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001492
Bill Buzbee270c1d62009-08-13 16:58:07 -07001493 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1494 sizeof(StackSaveArea) + (numArgs << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001495 /* generate null check */
1496 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001497 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001498 }
1499
1500 /*
1501 * Handle remaining 4n arguments:
1502 * store previously loaded 4 values and load the next 4 values
1503 */
1504 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001505 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001506 /*
1507 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001508 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001509 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001510 opImm(cUnit, OP_PUSH, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001511 /* No need to generate the loop structure if numArgs <= 11 */
1512 if (numArgs > 11) {
1513 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001514 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001515 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001516 storeMultiple(cUnit, r7, regMask);
1517 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001518 /* No need to generate the loop structure if numArgs <= 11 */
1519 if (numArgs > 11) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001520 opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001521 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1522 }
1523 }
1524
1525 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001526 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001527
1528 /* Generate the loop epilogue - don't use r0 */
1529 if ((numArgs > 4) && (numArgs % 4)) {
1530 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001531 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001532 }
1533 if (numArgs >= 8)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001534 opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001535
1536 /* Save the modulo 4 arguments */
1537 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001538 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001539 }
1540}
1541
Ben Cheng38329f52009-07-07 14:19:20 -07001542/*
1543 * Generate code to setup the call stack then jump to the chaining cell if it
1544 * is not a native method.
1545 */
1546static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001547 BasicBlock *bb, ArmLIR *labelList,
1548 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001549 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001550{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001551 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001552
1553 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001554 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001555 /* r4PC = dalvikCallsite */
1556 loadConstant(cUnit, r4PC,
1557 (int) (cUnit->method->insns + mir->offset));
1558 addrRetChain->generic.target = (LIR *) retChainingCell;
1559 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001560 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001561 * r1 = &ChainingCell
1562 * r4PC = callsiteDPC
1563 */
1564 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001565 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001566#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001567 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001568#endif
1569 } else {
1570 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1571#if defined(INVOKE_STATS)
1572 gDvmJit.invokeChain++;
1573#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001574 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001575 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1576 }
1577 /* Handle exceptions using the interpreter */
1578 genTrap(cUnit, mir->offset, pcrLabel);
1579}
1580
Ben Cheng38329f52009-07-07 14:19:20 -07001581/*
1582 * Generate code to check the validity of a predicted chain and take actions
1583 * based on the result.
1584 *
1585 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1586 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1587 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1588 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1589 * 0x426a99b2 : blx_2 see above --+
1590 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1591 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1592 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1593 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1594 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1595 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1596 * 0x426a99c0 : blx r7 --+
1597 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1598 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1599 * 0x426a99c6 : blx_2 see above --+
1600 */
1601static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1602 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001603 ArmLIR *retChainingCell,
1604 ArmLIR *predChainingCell,
1605 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001606{
1607 /* "this" is already left in r0 by genProcessArgs* */
1608
1609 /* r4PC = dalvikCallsite */
1610 loadConstant(cUnit, r4PC,
1611 (int) (cUnit->method->insns + mir->offset));
1612
1613 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001614 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001615 addrRetChain->generic.target = (LIR *) retChainingCell;
1616
1617 /* r2 = &predictedChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001618 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, OP_ADD, r2, rpc, 0,
1619 rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001620 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1621
1622 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1623
1624 /* return through lr - jump to the chaining cell */
1625 genUnconditionalBranch(cUnit, predChainingCell);
1626
1627 /*
1628 * null-check on "this" may have been eliminated, but we still need a PC-
1629 * reconstruction label for stack overflow bailout.
1630 */
1631 if (pcrLabel == NULL) {
1632 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001633 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1634 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001635 pcrLabel->operands[0] = dPC;
1636 pcrLabel->operands[1] = mir->offset;
1637 /* Insert the place holder to the growable list */
1638 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1639 }
1640
1641 /* return through lr+2 - punt to the interpreter */
1642 genUnconditionalBranch(cUnit, pcrLabel);
1643
1644 /*
1645 * return through lr+4 - fully resolve the callee method.
1646 * r1 <- count
1647 * r2 <- &predictedChainCell
1648 * r3 <- this->class
1649 * r4 <- dPC
1650 * r7 <- this->class->vtable
1651 */
1652
1653 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001654 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001655
1656 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001657 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001658
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001659 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001660 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001661
Bill Buzbee270c1d62009-08-13 16:58:07 -07001662 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1663 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001664
1665 /*
1666 * r0 = calleeMethod
1667 * r2 = &predictedChainingCell
1668 * r3 = class
1669 *
1670 * &returnChainingCell has been loaded into r1 but is not needed
1671 * when patching the chaining cell and will be clobbered upon
1672 * returning so it will be reconstructed again.
1673 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001674 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001675
1676 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001677 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001678 addrRetChain->generic.target = (LIR *) retChainingCell;
1679
1680 bypassRechaining->generic.target = (LIR *) addrRetChain;
1681 /*
1682 * r0 = calleeMethod,
1683 * r1 = &ChainingCell,
1684 * r4PC = callsiteDPC,
1685 */
1686 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1687#if defined(INVOKE_STATS)
1688 gDvmJit.invokePredictedChain++;
1689#endif
1690 /* Handle exceptions using the interpreter */
1691 genTrap(cUnit, mir->offset, pcrLabel);
1692}
1693
1694/*
1695 * Up calling this function, "this" is stored in r0. The actual class will be
1696 * chased down off r0 and the predicted one will be retrieved through
1697 * predictedChainingCell then a comparison is performed to see whether the
1698 * previously established chaining is still valid.
1699 *
1700 * The return LIR is a branch based on the comparison result. The actual branch
1701 * target will be setup in the caller.
1702 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001703static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1704 ArmLIR *predChainingCell,
1705 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001706 MIR *mir)
1707{
1708 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001709 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001710
1711 /*
1712 * r2 now contains predicted class. The starting offset of the
1713 * cached value is 4 bytes into the chaining cell.
1714 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001715 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001716 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07001717 getPredictedClass->generic.target = (LIR *) predChainingCell;
1718
1719 /*
1720 * r0 now contains predicted method. The starting offset of the
1721 * cached value is 8 bytes into the chaining cell.
1722 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001723 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001724 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001725 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1726
1727 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001728 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001729 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001730 getRechainingRequestCount->generic.target =
1731 (LIR *) predChainingCell;
1732
1733 /* r4PC = dalvikCallsite */
1734 loadConstant(cUnit, r4PC,
1735 (int) (cUnit->method->insns + mir->offset));
1736
1737 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001738 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001739 addrRetChain->generic.target = (LIR *) retChainingCell;
1740
1741 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001742 opRegReg(cUnit, OP_CMP, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001743
Bill Buzbee270c1d62009-08-13 16:58:07 -07001744 return opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001745}
1746
Ben Chengba4fc8b2009-06-01 13:00:29 -07001747/* Geneate a branch to go back to the interpreter */
1748static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1749{
1750 /* r0 = dalvik pc */
1751 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001752 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1753 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1754 jitToInterpEntries.dvmJitToInterpPunt), r1);
1755 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001756}
1757
1758/*
1759 * Attempt to single step one instruction using the interpreter and return
1760 * to the compiled code for the next Dalvik instruction
1761 */
1762static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1763{
1764 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1765 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1766 kInstrCanThrow;
1767 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1768 genPuntToInterp(cUnit, mir->offset);
1769 return;
1770 }
1771 int entryAddr = offsetof(InterpState,
1772 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001773 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001774 /* r0 = dalvik pc */
1775 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1776 /* r1 = dalvik pc of following instruction */
1777 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001778 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001779}
1780
Bill Buzbee270c1d62009-08-13 16:58:07 -07001781/* Generate conditional branch instructions */
1782static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1783 ArmConditionCode cond,
1784 ArmLIR *target)
1785{
1786 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
1787 branch->generic.target = (LIR *) target;
1788 return branch;
1789}
Ben Chengba4fc8b2009-06-01 13:00:29 -07001790
Bill Buzbee270c1d62009-08-13 16:58:07 -07001791/* Generate unconditional branch instructions */
1792static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1793{
1794 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
1795 branch->generic.target = (LIR *) target;
1796 return branch;
1797}
1798
1799/* Load the address of a Dalvik register on the frame */
1800static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
1801{
1802 return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
1803}
1804
1805/* Load a single value from rFP[src] and store them into rDest */
1806static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
1807{
1808 return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
1809}
1810
1811/* Load a word at base + displacement. Displacement must be word multiple */
1812static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
1813 int rDest)
1814{
1815 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
1816 -1);
1817}
1818
1819static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
1820 int displacement, int rSrc, int rScratch)
1821{
1822 return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
1823}
1824
1825/* Store a value from rSrc to vDest */
1826static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
1827 int rScratch)
1828{
1829 killNullCheckedRegister(cUnit, vDest);
1830 updateLiveRegister(cUnit, vDest, rSrc);
1831 return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
1832}
1833/*
1834 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
1835 * rDestHi
1836 */
1837static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
1838 int rDestHi)
1839{
1840 ArmLIR *res;
1841 /* Use reg + imm5*4 to load the values if possible */
1842 if (vSrc <= 30) {
1843 res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
1844 loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
1845 } else {
1846 assert(rDestLo < rDestHi);
1847 res = loadValueAddress(cUnit, vSrc, rDestLo);
1848 loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
1849 }
1850 return res;
1851}
1852
1853/*
1854 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
1855 * vDest+1
1856 */
1857static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
1858 int vDest, int rScratch)
1859{
1860 ArmLIR *res;
1861 killNullCheckedRegister(cUnit, vDest);
1862 killNullCheckedRegister(cUnit, vDest+1);
1863 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
1864
1865 /* Use reg + imm5*4 to store the values if possible */
1866 if (vDest <= 30) {
1867 res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
1868 storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
1869 } else {
1870 assert(rSrcLo < rSrcHi);
1871 res = loadValueAddress(cUnit, vDest, rScratch);
1872 storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
1873 }
1874 return res;
1875}
1876
1877static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1878{
1879 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
1880 dvmCompilerAppendLIR(cUnit, (LIR*)res);
1881 return res;
1882}
1883
Ben Chengba4fc8b2009-06-01 13:00:29 -07001884/*
1885 * The following are the first-level codegen routines that analyze the format
1886 * of each bytecode then either dispatch special purpose codegen routines
1887 * or produce corresponding Thumb instructions directly.
1888 */
1889
1890static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001891 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001892{
1893 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1894 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1895 return false;
1896}
1897
1898static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1899{
1900 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1901 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1902 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1903 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1904 return true;
1905 }
1906 switch (dalvikOpCode) {
1907 case OP_RETURN_VOID:
1908 genReturnCommon(cUnit,mir);
1909 break;
1910 case OP_UNUSED_73:
1911 case OP_UNUSED_79:
1912 case OP_UNUSED_7A:
1913 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1914 return true;
1915 case OP_NOP:
1916 break;
1917 default:
1918 return true;
1919 }
1920 return false;
1921}
1922
1923static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1924{
Ben Chenge9695e52009-06-16 16:11:47 -07001925 int reg0, reg1, reg2;
1926
Ben Chengba4fc8b2009-06-01 13:00:29 -07001927 switch (mir->dalvikInsn.opCode) {
1928 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001929 case OP_CONST_4: {
1930 /* Avoid using the previously used register */
1931 reg0 = selectFirstRegister(cUnit, vNone, false);
1932 reg1 = NEXT_REG(reg0);
1933 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1934 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001935 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001936 }
1937 case OP_CONST_WIDE_32: {
1938 /* Avoid using the previously used register */
1939 reg0 = selectFirstRegister(cUnit, vNone, true);
1940 reg1 = NEXT_REG(reg0);
1941 reg2 = NEXT_REG(reg1);
1942 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001943 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07001944 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001945 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001946 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001947 default:
1948 return true;
1949 }
1950 return false;
1951}
1952
1953static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1954{
Ben Chenge9695e52009-06-16 16:11:47 -07001955 int reg0, reg1, reg2;
1956
1957 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001958 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001959 case OP_CONST_HIGH16: {
1960 reg0 = selectFirstRegister(cUnit, vNone, false);
1961 reg1 = NEXT_REG(reg0);
1962 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1963 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001964 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001965 }
1966 case OP_CONST_WIDE_HIGH16: {
1967 reg0 = selectFirstRegister(cUnit, vNone, true);
1968 reg1 = NEXT_REG(reg0);
1969 reg2 = NEXT_REG(reg1);
1970 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1971 loadConstant(cUnit, reg0, 0);
1972 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001973 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001974 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001975 default:
1976 return true;
1977 }
1978 return false;
1979}
1980
1981static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1982{
1983 /* For OP_THROW_VERIFICATION_ERROR */
1984 genInterpSingleStep(cUnit, mir);
1985 return false;
1986}
1987
1988static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1989{
Ben Chenge9695e52009-06-16 16:11:47 -07001990 /* Native register to use if the interested value is vA */
1991 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1992 /* Native register to use if source is not from Dalvik registers */
1993 int regvNone = selectFirstRegister(cUnit, vNone, false);
1994 /* Similar to regvA but for 64-bit values */
1995 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
1996 /* Similar to regvNone but for 64-bit values */
1997 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
1998
Ben Chengba4fc8b2009-06-01 13:00:29 -07001999 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002000 case OP_CONST_STRING_JUMBO:
2001 case OP_CONST_STRING: {
2002 void *strPtr = (void*)
2003 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2004 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002005 loadConstant(cUnit, regvNone, (int) strPtr );
2006 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002007 break;
2008 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002009 case OP_CONST_CLASS: {
2010 void *classPtr = (void*)
2011 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2012 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002013 loadConstant(cUnit, regvNone, (int) classPtr );
2014 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002015 break;
2016 }
2017 case OP_SGET_OBJECT:
2018 case OP_SGET_BOOLEAN:
2019 case OP_SGET_CHAR:
2020 case OP_SGET_BYTE:
2021 case OP_SGET_SHORT:
2022 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002023 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002024 void *fieldPtr = (void*)
2025 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2026 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002027 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002028#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002029 loadWordDisp(cUnit, regvNone, 0, regvNone);
Jeff Hao97319a82009-08-12 16:57:15 -07002030#else
2031 int regMap = regvNone << 4 | regvNone;
2032 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2033
Jeff Hao97319a82009-08-12 16:57:15 -07002034#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002035 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002036 break;
2037 }
2038 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002039 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002040 void *fieldPtr = (void*)
2041 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002042 int reg0, reg1, reg2;
2043
Ben Chengba4fc8b2009-06-01 13:00:29 -07002044 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002045 reg0 = regvNoneWide;
2046 reg1 = NEXT_REG(reg0);
2047 reg2 = NEXT_REG(reg1);
2048 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002049#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002050 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002051#else
2052 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2053 selfVerificationMemOpWrapper(cUnit, regMap,
2054 &selfVerificationLoadDoubleword);
2055
Jeff Hao97319a82009-08-12 16:57:15 -07002056#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002057 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002058 break;
2059 }
2060 case OP_SPUT_OBJECT:
2061 case OP_SPUT_BOOLEAN:
2062 case OP_SPUT_CHAR:
2063 case OP_SPUT_BYTE:
2064 case OP_SPUT_SHORT:
2065 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002066 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002067 void *fieldPtr = (void*)
2068 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002069
Ben Chengba4fc8b2009-06-01 13:00:29 -07002070 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002071 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
2072 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
2073 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002074#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002075 storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
Jeff Hao97319a82009-08-12 16:57:15 -07002076#else
2077 int regMap = regvA << 4 | NEXT_REG(regvA);
2078 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2079#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002080 break;
2081 }
2082 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002083 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002084 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002085 void *fieldPtr = (void*)
2086 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002087
Ben Chengba4fc8b2009-06-01 13:00:29 -07002088 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002089 reg0 = regvAWide;
2090 reg1 = NEXT_REG(reg0);
2091 reg2 = NEXT_REG(reg1);
2092 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2093 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2094 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002095#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002096 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002097#else
2098 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2099 selfVerificationMemOpWrapper(cUnit, regMap,
2100 &selfVerificationStoreDoubleword);
2101#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002102 break;
2103 }
2104 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002105 /*
2106 * Obey the calling convention and don't mess with the register
2107 * usage.
2108 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002109 ClassObject *classPtr = (void*)
2110 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2111 assert(classPtr != NULL);
2112 assert(classPtr->status & CLASS_INITIALIZED);
2113 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
2114 /* It's going to throw, just let the interp. deal with it. */
2115 genInterpSingleStep(cUnit, mir);
2116 return false;
2117 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002118 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002119 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002120 genExportPC(cUnit, mir, r2, r3 );
2121 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002122 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002123 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002124 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2125 break;
2126 }
2127 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002128 /*
2129 * Obey the calling convention and don't mess with the register
2130 * usage.
2131 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002132 ClassObject *classPtr =
2133 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2134 loadConstant(cUnit, r1, (int) classPtr );
2135 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002136 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* Null? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002137 ArmLIR *branch1 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002138 opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002139 /* r0 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002140 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002141 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002142 opRegReg(cUnit, OP_CMP, r0, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002143 ArmLIR *branch2 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002144 opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2145 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002146 /* check cast failed - punt to the interpreter */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002147 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002148 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002149 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002150 branch1->generic.target = (LIR *)target;
2151 branch2->generic.target = (LIR *)target;
2152 break;
2153 }
2154 default:
2155 return true;
2156 }
2157 return false;
2158}
2159
2160static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2161{
2162 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2163 switch (dalvikOpCode) {
2164 case OP_MOVE_EXCEPTION: {
2165 int offset = offsetof(InterpState, self);
2166 int exOffset = offsetof(Thread, exception);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002167 loadWordDisp(cUnit, rGLUE, offset, r1);
2168 loadWordDisp(cUnit, r1, exOffset, r0);
Ben Chenge9695e52009-06-16 16:11:47 -07002169 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002170 break;
2171 }
2172 case OP_MOVE_RESULT:
2173 case OP_MOVE_RESULT_OBJECT: {
2174 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002175 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002176 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2177 break;
2178 }
2179 case OP_MOVE_RESULT_WIDE: {
2180 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002181 loadWordDisp(cUnit, rGLUE, offset, r0);
2182 loadWordDisp(cUnit, rGLUE, offset+4, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002183 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2184 break;
2185 }
2186 case OP_RETURN_WIDE: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002187 int vSrc = mir->dalvikInsn.vA;
2188 int reg0 = selectFirstRegister(cUnit, vSrc, true);
2189 int reg1 = NEXT_REG(reg0);
2190 int rScratch = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002191 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002192 loadValuePair(cUnit, vSrc, reg0, reg1);
2193 storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
2194 storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002195 genReturnCommon(cUnit,mir);
2196 break;
2197 }
2198 case OP_RETURN:
2199 case OP_RETURN_OBJECT: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002200 int vSrc = mir->dalvikInsn.vA;
2201 int reg0 = selectFirstRegister(cUnit, vSrc, false);
2202 int rScratch = NEXT_REG(reg0);
2203 loadValue(cUnit, vSrc, reg0);
2204 storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
2205 reg0, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002206 genReturnCommon(cUnit,mir);
2207 break;
2208 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002209 case OP_MONITOR_ENTER:
2210 case OP_MONITOR_EXIT: {
2211 int offset = offsetof(InterpState, self);
2212 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002213 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002214 if (dalvikOpCode == OP_MONITOR_ENTER) {
2215 loadConstant(cUnit, r2, (int)dvmLockObject);
2216 } else {
2217 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2218 }
Ben Chenge9695e52009-06-16 16:11:47 -07002219 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002220 /* Do the call */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002221 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002222 break;
2223 }
2224 case OP_THROW: {
2225 genInterpSingleStep(cUnit, mir);
2226 break;
2227 }
2228 default:
2229 return true;
2230 }
2231 return false;
2232}
2233
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002234static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002235{
2236 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002237
Ben Chengba4fc8b2009-06-01 13:00:29 -07002238 float __aeabi_i2f( int op1 );
2239 int __aeabi_f2iz( float op1 );
2240 float __aeabi_d2f( double op1 );
2241 double __aeabi_f2d( float op1 );
2242 double __aeabi_i2d( int op1 );
2243 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002244 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002245 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002246 s8 dvmJitf2l( float op1 );
2247 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002248
Bill Buzbeed45ba372009-06-15 17:00:57 -07002249 switch (opCode) {
2250 case OP_INT_TO_FLOAT:
2251 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2252 case OP_FLOAT_TO_INT:
2253 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2254 case OP_DOUBLE_TO_FLOAT:
2255 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2256 case OP_FLOAT_TO_DOUBLE:
2257 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2258 case OP_INT_TO_DOUBLE:
2259 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2260 case OP_DOUBLE_TO_INT:
2261 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2262 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002263 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002264 case OP_LONG_TO_FLOAT:
2265 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2266 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002267 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002268 case OP_LONG_TO_DOUBLE:
2269 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2270 default:
2271 return true;
2272 }
2273 return false;
2274}
2275
2276static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2277{
2278 OpCode opCode = mir->dalvikInsn.opCode;
2279 int vSrc1Dest = mir->dalvikInsn.vA;
2280 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002281 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002282
Ben Chengba4fc8b2009-06-01 13:00:29 -07002283 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2284 return genArithOp( cUnit, mir );
2285 }
2286
Ben Chenge9695e52009-06-16 16:11:47 -07002287 /*
2288 * If data type is 64-bit, re-calculate the register numbers in the
2289 * corresponding cases.
2290 */
2291 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2292 reg1 = NEXT_REG(reg0);
2293 reg2 = NEXT_REG(reg1);
2294
Ben Chengba4fc8b2009-06-01 13:00:29 -07002295 switch (opCode) {
2296 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002297 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002298 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002299 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002300 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002301 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002302 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002303 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002304 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002305 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002306 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002307 case OP_NEG_INT:
2308 case OP_NOT_INT:
2309 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2310 case OP_NEG_LONG:
2311 case OP_NOT_LONG:
2312 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2313 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002314 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002315 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002316 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07002317 case OP_MOVE_WIDE: {
2318 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2319 reg1 = NEXT_REG(reg0);
2320 reg2 = NEXT_REG(reg1);
2321
2322 loadValuePair(cUnit, vSrc2, reg0, reg1);
2323 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002324 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002325 }
2326 case OP_INT_TO_LONG: {
2327 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2328 reg1 = NEXT_REG(reg0);
2329 reg2 = NEXT_REG(reg1);
2330
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002331 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002332 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002333 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002334 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002335 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002336 case OP_MOVE:
2337 case OP_MOVE_OBJECT:
2338 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002339 loadValue(cUnit, vSrc2, reg0);
2340 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002341 break;
2342 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07002343 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002344 opRegReg(cUnit, OP_2BYTE, reg1, reg0);
2345 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002346 break;
2347 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07002348 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002349 opRegReg(cUnit, OP_2SHORT, reg1, reg0);
2350 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002351 break;
2352 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07002353 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002354 opRegReg(cUnit, OP_2CHAR, reg1, reg0);
2355 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002356 break;
2357 case OP_ARRAY_LENGTH: {
2358 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002359 loadValue(cUnit, vSrc2, reg1);
2360 genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
2361 loadWordDisp(cUnit, reg1, lenOffset, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -07002362 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002363 break;
2364 }
2365 default:
2366 return true;
2367 }
2368 return false;
2369}
2370
2371static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2372{
2373 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07002374 int reg0, reg1, reg2;
2375
Ben Chengba4fc8b2009-06-01 13:00:29 -07002376 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2377 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002378 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002379 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002380
2381 reg0 = selectFirstRegister(cUnit, vNone, true);
2382 reg1 = NEXT_REG(reg0);
2383 reg2 = NEXT_REG(reg1);
2384
2385 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002386 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002387
2388 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07002389 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002390 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002391 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002392 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002393
Ben Chenge9695e52009-06-16 16:11:47 -07002394 reg0 = selectFirstRegister(cUnit, vNone, false);
2395 reg1 = NEXT_REG(reg0);
2396
2397 loadConstant(cUnit, reg0, BBBB);
2398 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002399 } else {
2400 return true;
2401 }
2402 return false;
2403}
2404
2405/* Compare agaist zero */
2406static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002407 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002408{
2409 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002410 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002411 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002412
Ben Chenge9695e52009-06-16 16:11:47 -07002413 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002414 opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002415
Bill Buzbee270c1d62009-08-13 16:58:07 -07002416//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002417 switch (dalvikOpCode) {
2418 case OP_IF_EQZ:
2419 cond = ARM_COND_EQ;
2420 break;
2421 case OP_IF_NEZ:
2422 cond = ARM_COND_NE;
2423 break;
2424 case OP_IF_LTZ:
2425 cond = ARM_COND_LT;
2426 break;
2427 case OP_IF_GEZ:
2428 cond = ARM_COND_GE;
2429 break;
2430 case OP_IF_GTZ:
2431 cond = ARM_COND_GT;
2432 break;
2433 case OP_IF_LEZ:
2434 cond = ARM_COND_LE;
2435 break;
2436 default:
2437 cond = 0;
2438 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2439 dvmAbort();
2440 }
2441 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2442 /* This mostly likely will be optimized away in a later phase */
2443 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2444 return false;
2445}
2446
2447static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2448{
2449 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2450 int vSrc = mir->dalvikInsn.vB;
2451 int vDest = mir->dalvikInsn.vA;
2452 int lit = mir->dalvikInsn.vC;
Bill Buzbee270c1d62009-08-13 16:58:07 -07002453 OpKind op;
Ben Chenge9695e52009-06-16 16:11:47 -07002454 int reg0, reg1, regDest;
2455
2456 reg0 = selectFirstRegister(cUnit, vSrc, false);
2457 reg1 = NEXT_REG(reg0);
2458 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002459
Ben Chengba4fc8b2009-06-01 13:00:29 -07002460 int __aeabi_idivmod(int op1, int op2);
2461 int __aeabi_idiv(int op1, int op2);
2462
2463 switch (dalvikOpCode) {
2464 case OP_ADD_INT_LIT8:
2465 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002466 loadValue(cUnit, vSrc, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002467 opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
2468 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002469 break;
2470
2471 case OP_RSUB_INT_LIT8:
2472 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002473 loadValue(cUnit, vSrc, reg1);
2474 loadConstant(cUnit, reg0, lit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002475 opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
2476 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002477 break;
2478
2479 case OP_MUL_INT_LIT8:
2480 case OP_MUL_INT_LIT16:
2481 case OP_AND_INT_LIT8:
2482 case OP_AND_INT_LIT16:
2483 case OP_OR_INT_LIT8:
2484 case OP_OR_INT_LIT16:
2485 case OP_XOR_INT_LIT8:
2486 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002487 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002488 switch (dalvikOpCode) {
2489 case OP_MUL_INT_LIT8:
2490 case OP_MUL_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002491 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002492 break;
2493 case OP_AND_INT_LIT8:
2494 case OP_AND_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002495 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002496 break;
2497 case OP_OR_INT_LIT8:
2498 case OP_OR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002499 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002500 break;
2501 case OP_XOR_INT_LIT8:
2502 case OP_XOR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002503 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002504 break;
2505 default:
2506 dvmAbort();
2507 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002508 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2509 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002510 break;
2511
2512 case OP_SHL_INT_LIT8:
2513 case OP_SHR_INT_LIT8:
2514 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002515 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002516 switch (dalvikOpCode) {
2517 case OP_SHL_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002518 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002519 break;
2520 case OP_SHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002521 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002522 break;
2523 case OP_USHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002524 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002525 break;
2526 default: dvmAbort();
2527 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002528 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2529 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002530 break;
2531
2532 case OP_DIV_INT_LIT8:
2533 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002534 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002535 if (lit == 0) {
2536 /* Let the interpreter deal with div by 0 */
2537 genInterpSingleStep(cUnit, mir);
2538 return false;
2539 }
2540 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2541 loadConstant(cUnit, r1, lit);
2542 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002543 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002544 storeValue(cUnit, r0, vDest, r2);
2545 break;
2546
2547 case OP_REM_INT_LIT8:
2548 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002549 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002550 if (lit == 0) {
2551 /* Let the interpreter deal with div by 0 */
2552 genInterpSingleStep(cUnit, mir);
2553 return false;
2554 }
2555 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2556 loadConstant(cUnit, r1, lit);
2557 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002558 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002559 storeValue(cUnit, r1, vDest, r2);
2560 break;
2561 default:
2562 return true;
2563 }
2564 return false;
2565}
2566
2567static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2568{
2569 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2570 int fieldOffset;
2571
2572 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2573 InstField *pInstField = (InstField *)
2574 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2575 int fieldOffset;
2576
2577 assert(pInstField != NULL);
2578 fieldOffset = pInstField->byteOffset;
2579 } else {
2580 /* To make the compiler happy */
2581 fieldOffset = 0;
2582 }
2583 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002584 case OP_NEW_ARRAY: {
2585 void *classPtr = (void*)
2586 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2587 assert(classPtr != NULL);
2588 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2589 loadConstant(cUnit, r0, (int) classPtr );
2590 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002591 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002592 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2593 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002594 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2595 opReg(cUnit, OP_BLX, r4PC);
2596 /* Note: on failure, we'll bail and reinterpret */
Ben Chenge9695e52009-06-16 16:11:47 -07002597 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002598 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2599 break;
2600 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002601 case OP_INSTANCE_OF: {
2602 ClassObject *classPtr =
2603 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2604 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002605 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002606 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002607//TUNING: compare to 0 primative to allow use of CB[N]Z
2608 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002609 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002610 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002611 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002612 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002613 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002614 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002615 opRegReg(cUnit, OP_CMP, r1, r2);
2616 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2617 opRegReg(cUnit, OP_MOV, r0, r1);
2618 opRegReg(cUnit, OP_MOV, r1, r2);
2619 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002620 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002621 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002622 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2623 branch1->generic.target = (LIR *)target;
2624 branch2->generic.target = (LIR *)target;
2625 break;
2626 }
2627 case OP_IGET_WIDE:
2628 genIGetWide(cUnit, mir, fieldOffset);
2629 break;
2630 case OP_IGET:
2631 case OP_IGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002632 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002633 break;
2634 case OP_IGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002635 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002636 break;
2637 case OP_IGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002638 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002639 break;
2640 case OP_IGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002641 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002642 break;
2643 case OP_IGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002644 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002645 break;
2646 case OP_IPUT_WIDE:
2647 genIPutWide(cUnit, mir, fieldOffset);
2648 break;
2649 case OP_IPUT:
2650 case OP_IPUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002651 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002652 break;
2653 case OP_IPUT_SHORT:
2654 case OP_IPUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002655 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002656 break;
2657 case OP_IPUT_BYTE:
2658 case OP_IPUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002659 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002660 break;
2661 default:
2662 return true;
2663 }
2664 return false;
2665}
2666
2667static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2668{
2669 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2670 int fieldOffset = mir->dalvikInsn.vC;
2671 switch (dalvikOpCode) {
2672 case OP_IGET_QUICK:
2673 case OP_IGET_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002674 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002675 break;
2676 case OP_IPUT_QUICK:
2677 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002678 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002679 break;
2680 case OP_IGET_WIDE_QUICK:
2681 genIGetWide(cUnit, mir, fieldOffset);
2682 break;
2683 case OP_IPUT_WIDE_QUICK:
2684 genIPutWide(cUnit, mir, fieldOffset);
2685 break;
2686 default:
2687 return true;
2688 }
2689 return false;
2690
2691}
2692
2693/* Compare agaist zero */
2694static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002695 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002696{
2697 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002698 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002699 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002700
Ben Chenge9695e52009-06-16 16:11:47 -07002701 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2702 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2703 reg1 = NEXT_REG(reg0);
2704 /* Load vB first since vA can be fetched via a move */
2705 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2706 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2707 } else {
2708 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2709 reg1 = NEXT_REG(reg0);
2710 /* Load vA first since vB can be fetched via a move */
2711 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2712 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2713 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002714 opRegReg(cUnit, OP_CMP, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002715
2716 switch (dalvikOpCode) {
2717 case OP_IF_EQ:
2718 cond = ARM_COND_EQ;
2719 break;
2720 case OP_IF_NE:
2721 cond = ARM_COND_NE;
2722 break;
2723 case OP_IF_LT:
2724 cond = ARM_COND_LT;
2725 break;
2726 case OP_IF_GE:
2727 cond = ARM_COND_GE;
2728 break;
2729 case OP_IF_GT:
2730 cond = ARM_COND_GT;
2731 break;
2732 case OP_IF_LE:
2733 cond = ARM_COND_LE;
2734 break;
2735 default:
2736 cond = 0;
2737 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2738 dvmAbort();
2739 }
2740 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2741 /* This mostly likely will be optimized away in a later phase */
2742 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2743 return false;
2744}
2745
2746static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2747{
2748 OpCode opCode = mir->dalvikInsn.opCode;
2749 int vSrc1Dest = mir->dalvikInsn.vA;
2750 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002751 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002752
2753 switch (opCode) {
2754 case OP_MOVE_16:
2755 case OP_MOVE_OBJECT_16:
2756 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002757 case OP_MOVE_OBJECT_FROM16: {
2758 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2759 reg1 = NEXT_REG(reg0);
2760 loadValue(cUnit, vSrc2, reg0);
2761 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002762 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002763 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002764 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002765 case OP_MOVE_WIDE_FROM16: {
2766 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2767 reg1 = NEXT_REG(reg0);
2768 reg2 = NEXT_REG(reg1);
2769 loadValuePair(cUnit, vSrc2, reg0, reg1);
2770 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002771 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002772 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002773 default:
2774 return true;
2775 }
2776 return false;
2777}
2778
2779static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2780{
2781 OpCode opCode = mir->dalvikInsn.opCode;
2782 int vA = mir->dalvikInsn.vA;
2783 int vB = mir->dalvikInsn.vB;
2784 int vC = mir->dalvikInsn.vC;
2785
Ben Chenge9695e52009-06-16 16:11:47 -07002786 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002787 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2788 return genArithOp( cUnit, mir );
2789 }
2790
2791 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002792 case OP_CMPL_FLOAT:
2793 case OP_CMPG_FLOAT:
2794 case OP_CMPL_DOUBLE:
2795 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002796 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002797 case OP_CMP_LONG:
Bill Buzbeea4a7f072009-08-27 13:58:09 -07002798 genCmpLong(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002799 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002800 case OP_AGET_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002801 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002802 break;
2803 case OP_AGET:
2804 case OP_AGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002805 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002806 break;
2807 case OP_AGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002808 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002809 break;
2810 case OP_AGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002811 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002812 break;
2813 case OP_AGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002814 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002815 break;
2816 case OP_AGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002817 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002818 break;
2819 case OP_APUT_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002820 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002821 break;
2822 case OP_APUT:
2823 case OP_APUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002824 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002825 break;
2826 case OP_APUT_SHORT:
2827 case OP_APUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002828 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002829 break;
2830 case OP_APUT_BYTE:
2831 case OP_APUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002832 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002833 break;
2834 default:
2835 return true;
2836 }
2837 return false;
2838}
2839
2840static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2841{
2842 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2843 switch (dalvikOpCode) {
2844 case OP_FILL_ARRAY_DATA: {
2845 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2846 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2847 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2848 (int) (cUnit->method->insns + mir->offset));
2849 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002850 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002851 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002852 break;
2853 }
2854 /*
2855 * TODO
2856 * - Add a 1 to 3-entry per-location cache here to completely
2857 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2858 * - Use out-of-line handlers for both of these
2859 */
2860 case OP_PACKED_SWITCH:
2861 case OP_SPARSE_SWITCH: {
2862 if (dalvikOpCode == OP_PACKED_SWITCH) {
2863 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2864 } else {
2865 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2866 }
2867 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2868 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2869 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002870 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002871 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002872 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2873 jitToInterpEntries.dvmJitToInterpNoChain), r2);
2874 opRegReg(cUnit, OP_ADD, r0, r0);
2875 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
2876 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002877 break;
2878 }
2879 default:
2880 return true;
2881 }
2882 return false;
2883}
2884
2885static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002886 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002887{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07002888 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002889 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002890
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07002891 if (bb->fallThrough != NULL)
2892 retChainingCell = &labelList[bb->fallThrough->id];
2893
Ben Chengba4fc8b2009-06-01 13:00:29 -07002894 DecodedInstruction *dInsn = &mir->dalvikInsn;
2895 switch (mir->dalvikInsn.opCode) {
2896 /*
2897 * calleeMethod = this->clazz->vtable[
2898 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2899 * ]
2900 */
2901 case OP_INVOKE_VIRTUAL:
2902 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002903 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002904 int methodIndex =
2905 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2906 methodIndex;
2907
2908 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2909 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2910 else
2911 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2912
Ben Cheng38329f52009-07-07 14:19:20 -07002913 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2914 retChainingCell,
2915 predChainingCell,
2916 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002917 break;
2918 }
2919 /*
2920 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2921 * ->pResMethods[BBBB]->methodIndex]
2922 */
2923 /* TODO - not excersized in RunPerf.jar */
2924 case OP_INVOKE_SUPER:
2925 case OP_INVOKE_SUPER_RANGE: {
2926 int mIndex = cUnit->method->clazz->pDvmDex->
2927 pResMethods[dInsn->vB]->methodIndex;
2928 const Method *calleeMethod =
2929 cUnit->method->clazz->super->vtable[mIndex];
2930
2931 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2932 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2933 else
2934 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2935
2936 /* r0 = calleeMethod */
2937 loadConstant(cUnit, r0, (int) calleeMethod);
2938
Ben Cheng38329f52009-07-07 14:19:20 -07002939 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2940 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002941 break;
2942 }
2943 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2944 case OP_INVOKE_DIRECT:
2945 case OP_INVOKE_DIRECT_RANGE: {
2946 const Method *calleeMethod =
2947 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2948
2949 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2950 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2951 else
2952 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2953
2954 /* r0 = calleeMethod */
2955 loadConstant(cUnit, r0, (int) calleeMethod);
2956
Ben Cheng38329f52009-07-07 14:19:20 -07002957 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2958 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002959 break;
2960 }
2961 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2962 case OP_INVOKE_STATIC:
2963 case OP_INVOKE_STATIC_RANGE: {
2964 const Method *calleeMethod =
2965 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2966
2967 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2968 genProcessArgsNoRange(cUnit, mir, dInsn,
2969 NULL /* no null check */);
2970 else
2971 genProcessArgsRange(cUnit, mir, dInsn,
2972 NULL /* no null check */);
2973
2974 /* r0 = calleeMethod */
2975 loadConstant(cUnit, r0, (int) calleeMethod);
2976
Ben Cheng38329f52009-07-07 14:19:20 -07002977 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2978 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002979 break;
2980 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002981/*
2982 * TODO: When we move to using upper registers in Thumb2, make sure
2983 * the register allocater is told that r9, r10, & r12 are killed
2984 * here.
2985 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002986 /*
2987 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2988 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07002989 *
2990 * Given "invoke-interface {v0}", the following is the generated code:
2991 *
2992 * 0x426a9abe : ldr r0, [r5, #0] --+
2993 * 0x426a9ac0 : mov r7, r5 |
2994 * 0x426a9ac2 : sub r7, #24 |
2995 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2996 * 0x426a9ac6 : beq 0x426a9afe |
2997 * 0x426a9ac8 : stmia r7, <r0> --+
2998 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2999 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3000 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3001 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3002 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3003 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3004 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
3005 * 0x426a9ad8 : mov r9, r1 --+
3006 * 0x426a9ada : mov r10, r2 |
3007 * 0x426a9adc : mov r12, r3 |
3008 * 0x426a9ade : mov r0, r3 |
3009 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3010 * 0x426a9ae2 : ldr r2, [pc, #76] |
3011 * 0x426a9ae4 : ldr r3, [pc, #68] |
3012 * 0x426a9ae6 : ldr r7, [pc, #64] |
3013 * 0x426a9ae8 : blx r7 --+
3014 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
3015 * 0x426a9aec : cmp r1, #0 --> compare against 0
3016 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3017 * 0x426a9af0 : ldr r7, [r6, #96] --+
3018 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3019 * 0x426a9af4 : mov r3, r12 |
3020 * 0x426a9af6 : blx r7 --+
3021 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3022 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3023 * 0x426a9afc : blx_2 see above --+
3024 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3025 * 0x426a9afe (0042): ldr r0, [pc, #52]
3026 * Exception_Handling:
3027 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3028 * 0x426a9b02 (0046): blx r1
3029 * 0x426a9b04 (0048): .align4
3030 * -------- chaining cell (hot): 0x0021
3031 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3032 * 0x426a9b06 (004a): blx r0
3033 * 0x426a9b08 (004c): data 0x7872(30834)
3034 * 0x426a9b0a (004e): data 0x428b(17035)
3035 * 0x426a9b0c (0050): .align4
3036 * -------- chaining cell (predicted)
3037 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3038 * 0x426a9b0e (0052): data 0x0000(0)
3039 * 0x426a9b10 (0054): data 0x0000(0) --> class
3040 * 0x426a9b12 (0056): data 0x0000(0)
3041 * 0x426a9b14 (0058): data 0x0000(0) --> method
3042 * 0x426a9b16 (005a): data 0x0000(0)
3043 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3044 * 0x426a9b1a (005e): data 0x0000(0)
3045 * 0x426a9b28 (006c): .word (0xad0392a5)
3046 * 0x426a9b2c (0070): .word (0x6e750)
3047 * 0x426a9b30 (0074): .word (0x4109a618)
3048 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003049 */
3050 case OP_INVOKE_INTERFACE:
3051 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003052 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003053 int methodIndex = dInsn->vB;
3054
3055 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3056 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3057 else
3058 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3059
Ben Cheng38329f52009-07-07 14:19:20 -07003060 /* "this" is already left in r0 by genProcessArgs* */
3061
3062 /* r4PC = dalvikCallsite */
3063 loadConstant(cUnit, r4PC,
3064 (int) (cUnit->method->insns + mir->offset));
3065
3066 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003067 ArmLIR *addrRetChain =
3068 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003069 addrRetChain->generic.target = (LIR *) retChainingCell;
3070
3071 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003072 ArmLIR *predictedChainingCell =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003073 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003074 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3075
3076 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3077
3078 /* return through lr - jump to the chaining cell */
3079 genUnconditionalBranch(cUnit, predChainingCell);
3080
3081 /*
3082 * null-check on "this" may have been eliminated, but we still need
3083 * a PC-reconstruction label for stack overflow bailout.
3084 */
3085 if (pcrLabel == NULL) {
3086 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003087 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3088 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003089 pcrLabel->operands[0] = dPC;
3090 pcrLabel->operands[1] = mir->offset;
3091 /* Insert the place holder to the growable list */
3092 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3093 }
3094
3095 /* return through lr+2 - punt to the interpreter */
3096 genUnconditionalBranch(cUnit, pcrLabel);
3097
3098 /*
3099 * return through lr+4 - fully resolve the callee method.
3100 * r1 <- count
3101 * r2 <- &predictedChainCell
3102 * r3 <- this->class
3103 * r4 <- dPC
3104 * r7 <- this->class->vtable
3105 */
3106
3107 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003108 opRegReg(cUnit, OP_MOV, r9, r1);
3109 opRegReg(cUnit, OP_MOV, r10, r2);
3110 opRegReg(cUnit, OP_MOV, r12, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003111
Ben Chengba4fc8b2009-06-01 13:00:29 -07003112 /* r0 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003113 opRegReg(cUnit, OP_MOV, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003114
3115 /* r1 = BBBB */
3116 loadConstant(cUnit, r1, dInsn->vB);
3117
3118 /* r2 = method (caller) */
3119 loadConstant(cUnit, r2, (int) cUnit->method);
3120
3121 /* r3 = pDvmDex */
3122 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3123
3124 loadConstant(cUnit, r7,
3125 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003126 opReg(cUnit, OP_BLX, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003127
3128 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3129
Bill Buzbee270c1d62009-08-13 16:58:07 -07003130 opRegReg(cUnit, OP_MOV, r1, r9);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003131
Ben Cheng38329f52009-07-07 14:19:20 -07003132 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003133 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003134
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003135 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003136 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07003137
Bill Buzbee270c1d62009-08-13 16:58:07 -07003138 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3139 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003140
Bill Buzbee270c1d62009-08-13 16:58:07 -07003141 opRegReg(cUnit, OP_MOV, r2, r10);
3142 opRegReg(cUnit, OP_MOV, r3, r12);
Ben Cheng38329f52009-07-07 14:19:20 -07003143
3144 /*
3145 * r0 = calleeMethod
3146 * r2 = &predictedChainingCell
3147 * r3 = class
3148 *
3149 * &returnChainingCell has been loaded into r1 but is not needed
3150 * when patching the chaining cell and will be clobbered upon
3151 * returning so it will be reconstructed again.
3152 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003153 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003154
3155 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003156 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003157 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003158
3159 bypassRechaining->generic.target = (LIR *) addrRetChain;
3160
Ben Chengba4fc8b2009-06-01 13:00:29 -07003161 /*
3162 * r0 = this, r1 = calleeMethod,
3163 * r1 = &ChainingCell,
3164 * r4PC = callsiteDPC,
3165 */
3166 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3167#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003168 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003169#endif
3170 /* Handle exceptions using the interpreter */
3171 genTrap(cUnit, mir->offset, pcrLabel);
3172 break;
3173 }
3174 /* NOP */
3175 case OP_INVOKE_DIRECT_EMPTY: {
3176 return false;
3177 }
3178 case OP_FILLED_NEW_ARRAY:
3179 case OP_FILLED_NEW_ARRAY_RANGE: {
3180 /* Just let the interpreter deal with these */
3181 genInterpSingleStep(cUnit, mir);
3182 break;
3183 }
3184 default:
3185 return true;
3186 }
3187 return false;
3188}
3189
3190static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003191 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003192{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003193 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3194 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3195 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003196
3197 DecodedInstruction *dInsn = &mir->dalvikInsn;
3198 switch (mir->dalvikInsn.opCode) {
3199 /* calleeMethod = this->clazz->vtable[BBBB] */
3200 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3201 case OP_INVOKE_VIRTUAL_QUICK: {
3202 int methodIndex = dInsn->vB;
3203 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3204 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3205 else
3206 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3207
Ben Cheng38329f52009-07-07 14:19:20 -07003208 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3209 retChainingCell,
3210 predChainingCell,
3211 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003212 break;
3213 }
3214 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3215 case OP_INVOKE_SUPER_QUICK:
3216 case OP_INVOKE_SUPER_QUICK_RANGE: {
3217 const Method *calleeMethod =
3218 cUnit->method->clazz->super->vtable[dInsn->vB];
3219
3220 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3221 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3222 else
3223 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3224
3225 /* r0 = calleeMethod */
3226 loadConstant(cUnit, r0, (int) calleeMethod);
3227
Ben Cheng38329f52009-07-07 14:19:20 -07003228 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3229 calleeMethod);
3230 /* Handle exceptions using the interpreter */
3231 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003232 break;
3233 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003234 default:
3235 return true;
3236 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003237 return false;
3238}
3239
3240/*
3241 * NOTE: We assume here that the special native inline routines
3242 * are side-effect free. By making this assumption, we can safely
3243 * re-execute the routine from the interpreter if it decides it
3244 * wants to throw an exception. We still need to EXPORT_PC(), though.
3245 */
3246static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3247{
3248 DecodedInstruction *dInsn = &mir->dalvikInsn;
3249 switch( mir->dalvikInsn.opCode) {
3250 case OP_EXECUTE_INLINE: {
3251 unsigned int i;
3252 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003253 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003254 int operation = dInsn->vB;
3255
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003256 switch (operation) {
3257 case INLINE_EMPTYINLINEMETHOD:
3258 return false; /* Nop */
3259 case INLINE_STRING_LENGTH:
3260 return genInlinedStringLength(cUnit, mir);
3261 case INLINE_MATH_ABS_INT:
3262 return genInlinedAbsInt(cUnit, mir);
3263 case INLINE_MATH_ABS_LONG:
3264 return genInlinedAbsLong(cUnit, mir);
3265 case INLINE_MATH_MIN_INT:
3266 return genInlinedMinMaxInt(cUnit, mir, true);
3267 case INLINE_MATH_MAX_INT:
3268 return genInlinedMinMaxInt(cUnit, mir, false);
3269 case INLINE_STRING_CHARAT:
3270 return genInlinedStringCharAt(cUnit, mir);
3271 case INLINE_MATH_SQRT:
3272 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003273 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003274 else
3275 break; /* Handle with C routine */
3276 case INLINE_MATH_COS:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003277 case INLINE_MATH_SIN:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003278 break; /* Handle with C routine */
3279 case INLINE_MATH_ABS_FLOAT:
3280 return genInlinedAbsFloat(cUnit, mir);
3281 case INLINE_MATH_ABS_DOUBLE:
3282 return genInlinedAbsDouble(cUnit, mir);
3283 case INLINE_STRING_COMPARETO:
3284 case INLINE_STRING_EQUALS:
3285 break;
3286 default:
3287 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003288 }
3289
3290 /* Materialize pointer to retval & push */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003291 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3292 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3293
Ben Chengba4fc8b2009-06-01 13:00:29 -07003294 /* Push r4 and (just to take up space) r5) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003295 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003296
3297 /* Get code pointer to inline routine */
3298 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3299
3300 /* Export PC */
3301 genExportPC(cUnit, mir, r0, r1 );
3302
3303 /* Load arguments to r0 through r3 as applicable */
3304 for (i=0; i < dInsn->vA; i++) {
3305 loadValue(cUnit, dInsn->arg[i], i);
3306 }
3307 /* Call inline routine */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003308 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003309
3310 /* Strip frame */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003311 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003312
3313 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003314 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003315
Ben Chenge9695e52009-06-16 16:11:47 -07003316 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003317 break;
3318 }
3319 default:
3320 return true;
3321 }
3322 return false;
3323}
3324
3325static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3326{
3327 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3328 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3329 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3330 return false;
3331}
3332
Ben Chengba4fc8b2009-06-01 13:00:29 -07003333/*
3334 * The following are special processing routines that handle transfer of
3335 * controls between compiled code and the interpreter. Certain VM states like
3336 * Dalvik PC and special-purpose registers are reconstructed here.
3337 */
3338
Ben Cheng1efc9c52009-06-08 18:25:27 -07003339/* Chaining cell for code that may need warmup. */
3340static void handleNormalChainingCell(CompilationUnit *cUnit,
3341 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003342{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003343 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3344 jitToInterpEntries.dvmJitToInterpNormal), r0);
3345 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003346 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3347}
3348
3349/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003350 * Chaining cell for instructions that immediately following already translated
3351 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003352 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003353static void handleHotChainingCell(CompilationUnit *cUnit,
3354 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003355{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003356 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3357 jitToInterpEntries.dvmJitToTraceSelect), r0);
3358 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003359 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3360}
3361
Jeff Hao97319a82009-08-12 16:57:15 -07003362#if defined(WITH_SELF_VERIFICATION)
3363/* Chaining cell for branches that branch back into the same basic block */
3364static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3365 unsigned int offset)
3366{
3367 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3368 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
3369 newLIR1(cUnit, THUMB_BLX_R, r0);
3370 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3371}
3372
3373#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003374/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003375static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3376 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003377{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003378 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3379 jitToInterpEntries.dvmJitToTraceSelect), r0);
3380 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003381 addWordData(cUnit, (int) (callee->insns), true);
3382}
3383
Ben Cheng38329f52009-07-07 14:19:20 -07003384/* Chaining cell for monomorphic method invocations. */
3385static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3386{
3387
3388 /* Should not be executed in the initial state */
3389 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3390 /* To be filled: class */
3391 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3392 /* To be filled: method */
3393 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3394 /*
3395 * Rechain count. The initial value of 0 here will trigger chaining upon
3396 * the first invocation of this callsite.
3397 */
3398 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3399}
3400
Ben Chengba4fc8b2009-06-01 13:00:29 -07003401/* Load the Dalvik PC into r0 and jump to the specified target */
3402static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003403 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003404{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003405 ArmLIR **pcrLabel =
3406 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003407 int numElems = cUnit->pcReconstructionList.numUsed;
3408 int i;
3409 for (i = 0; i < numElems; i++) {
3410 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3411 /* r0 = dalvik PC */
3412 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3413 genUnconditionalBranch(cUnit, targetLabel);
3414 }
3415}
3416
3417/* Entry function to invoke the backend of the JIT compiler */
3418void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3419{
3420 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003421 ArmLIR *labelList =
3422 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003423 GrowableList chainingListByType[CHAINING_CELL_LAST];
3424 int i;
3425
3426 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003427 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003428 */
3429 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3430 dvmInitGrowableList(&chainingListByType[i], 2);
3431 }
3432
3433 BasicBlock **blockList = cUnit->blockList;
3434
Bill Buzbee6e963e12009-06-17 16:56:19 -07003435 if (cUnit->executionCount) {
3436 /*
3437 * Reserve 6 bytes at the beginning of the trace
3438 * +----------------------------+
3439 * | execution count (4 bytes) |
3440 * +----------------------------+
3441 * | chain cell offset (2 bytes)|
3442 * +----------------------------+
3443 * ...and then code to increment the execution
3444 * count:
3445 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3446 * sub r0, #10 @ back up to addr of executionCount
3447 * ldr r1, [r0]
3448 * add r1, #1
3449 * str r1, [r0]
3450 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003451 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3452 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003453 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003454 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003455 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003456 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003457 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc & THUMB_REG_MASK);
3458 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3459 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3460 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3461 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003462 } else {
3463 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003464 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003465 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003466 cUnit->headerSize = 2;
3467 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003468
Ben Chengba4fc8b2009-06-01 13:00:29 -07003469 /* Handle the content in each basic block */
3470 for (i = 0; i < cUnit->numBlocks; i++) {
3471 blockList[i]->visited = true;
3472 MIR *mir;
3473
3474 labelList[i].operands[0] = blockList[i]->startOffset;
3475
3476 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3477 /*
3478 * Append the label pseudo LIR first. Chaining cells will be handled
3479 * separately afterwards.
3480 */
3481 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3482 }
3483
3484 if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003485 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003486 /* Reset the register state */
3487 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003488 } else {
3489 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003490 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003491 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003492 /* handle the codegen later */
3493 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003494 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003495 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003496 case CHAINING_CELL_INVOKE_SINGLETON:
3497 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003498 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003499 labelList[i].operands[0] =
3500 (int) blockList[i]->containingMethod;
3501 /* handle the codegen later */
3502 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003503 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3504 (void *) i);
3505 break;
3506 case CHAINING_CELL_INVOKE_PREDICTED:
3507 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003508 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003509 /* handle the codegen later */
3510 dvmInsertGrowableList(
3511 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3512 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003513 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003514 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003515 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003516 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003517 /* handle the codegen later */
3518 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003519 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003520 (void *) i);
3521 break;
3522 case PC_RECONSTRUCTION:
3523 /* Make sure exception handling block is next */
3524 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003525 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003526 assert (i == cUnit->numBlocks - 2);
3527 handlePCReconstruction(cUnit, &labelList[i+1]);
3528 break;
3529 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003530 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003531 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003532 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3533 jitToInterpEntries.dvmJitToInterpPunt),
3534 r1);
3535 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003536 }
3537 break;
Jeff Hao97319a82009-08-12 16:57:15 -07003538#if defined(WITH_SELF_VERIFICATION)
3539 case CHAINING_CELL_BACKWARD_BRANCH:
3540 labelList[i].opCode =
3541 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3542 /* handle the codegen later */
3543 dvmInsertGrowableList(
3544 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3545 (void *) i);
3546 break;
3547#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003548 default:
3549 break;
3550 }
3551 continue;
3552 }
Ben Chenge9695e52009-06-16 16:11:47 -07003553
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003554 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003555
Ben Chengba4fc8b2009-06-01 13:00:29 -07003556 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3557 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3558 InstructionFormat dalvikFormat =
3559 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003560 ArmLIR *boundaryLIR =
3561 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Chenge9695e52009-06-16 16:11:47 -07003562 mir->offset,dalvikOpCode);
3563 /* Remember the first LIR for this block */
3564 if (headLIR == NULL) {
3565 headLIR = boundaryLIR;
3566 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003567 bool notHandled;
3568 /*
3569 * Debugging: screen the opcode first to see if it is in the
3570 * do[-not]-compile list
3571 */
3572 bool singleStepMe =
3573 gDvmJit.includeSelectedOp !=
3574 ((gDvmJit.opList[dalvikOpCode >> 3] &
3575 (1 << (dalvikOpCode & 0x7))) !=
3576 0);
Jeff Hao97319a82009-08-12 16:57:15 -07003577#if defined(WITH_SELF_VERIFICATION)
3578 /* Punt on opcodes we can't replay */
3579 if (selfVerificationPuntOps(dalvikOpCode))
3580 singleStepMe = true;
3581#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003582 if (singleStepMe || cUnit->allSingleStep) {
3583 notHandled = false;
3584 genInterpSingleStep(cUnit, mir);
3585 } else {
3586 opcodeCoverage[dalvikOpCode]++;
3587 switch (dalvikFormat) {
3588 case kFmt10t:
3589 case kFmt20t:
3590 case kFmt30t:
3591 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3592 mir, blockList[i], labelList);
3593 break;
3594 case kFmt10x:
3595 notHandled = handleFmt10x(cUnit, mir);
3596 break;
3597 case kFmt11n:
3598 case kFmt31i:
3599 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3600 break;
3601 case kFmt11x:
3602 notHandled = handleFmt11x(cUnit, mir);
3603 break;
3604 case kFmt12x:
3605 notHandled = handleFmt12x(cUnit, mir);
3606 break;
3607 case kFmt20bc:
3608 notHandled = handleFmt20bc(cUnit, mir);
3609 break;
3610 case kFmt21c:
3611 case kFmt31c:
3612 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3613 break;
3614 case kFmt21h:
3615 notHandled = handleFmt21h(cUnit, mir);
3616 break;
3617 case kFmt21s:
3618 notHandled = handleFmt21s(cUnit, mir);
3619 break;
3620 case kFmt21t:
3621 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3622 labelList);
3623 break;
3624 case kFmt22b:
3625 case kFmt22s:
3626 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3627 break;
3628 case kFmt22c:
3629 notHandled = handleFmt22c(cUnit, mir);
3630 break;
3631 case kFmt22cs:
3632 notHandled = handleFmt22cs(cUnit, mir);
3633 break;
3634 case kFmt22t:
3635 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3636 labelList);
3637 break;
3638 case kFmt22x:
3639 case kFmt32x:
3640 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3641 break;
3642 case kFmt23x:
3643 notHandled = handleFmt23x(cUnit, mir);
3644 break;
3645 case kFmt31t:
3646 notHandled = handleFmt31t(cUnit, mir);
3647 break;
3648 case kFmt3rc:
3649 case kFmt35c:
3650 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3651 labelList);
3652 break;
3653 case kFmt3rms:
3654 case kFmt35ms:
3655 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3656 labelList);
3657 break;
3658 case kFmt3inline:
3659 notHandled = handleFmt3inline(cUnit, mir);
3660 break;
3661 case kFmt51l:
3662 notHandled = handleFmt51l(cUnit, mir);
3663 break;
3664 default:
3665 notHandled = true;
3666 break;
3667 }
3668 }
3669 if (notHandled) {
3670 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3671 mir->offset,
3672 dalvikOpCode, getOpcodeName(dalvikOpCode),
3673 dalvikFormat);
3674 dvmAbort();
3675 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003676 }
3677 }
Ben Chenge9695e52009-06-16 16:11:47 -07003678 /* Eliminate redundant loads/stores and delay stores into later slots */
3679 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3680 cUnit->lastLIRInsn);
Ben Cheng1efc9c52009-06-08 18:25:27 -07003681 /*
3682 * Check if the block is terminated due to trace length constraint -
3683 * insert an unconditional branch to the chaining cell.
3684 */
3685 if (blockList[i]->needFallThroughBranch) {
3686 genUnconditionalBranch(cUnit,
3687 &labelList[blockList[i]->fallThrough->id]);
3688 }
3689
Ben Chengba4fc8b2009-06-01 13:00:29 -07003690 }
3691
Ben Chenge9695e52009-06-16 16:11:47 -07003692 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003693 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3694 size_t j;
3695 int *blockIdList = (int *) chainingListByType[i].elemList;
3696
3697 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3698
3699 /* No chaining cells of this type */
3700 if (cUnit->numChainingCells[i] == 0)
3701 continue;
3702
3703 /* Record the first LIR for a new type of chaining cell */
3704 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3705
3706 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3707 int blockId = blockIdList[j];
3708
3709 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003710 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003711
3712 /* Insert the pseudo chaining instruction */
3713 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3714
3715
3716 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003717 case CHAINING_CELL_NORMAL:
3718 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003719 blockList[blockId]->startOffset);
3720 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003721 case CHAINING_CELL_INVOKE_SINGLETON:
3722 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003723 blockList[blockId]->containingMethod);
3724 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003725 case CHAINING_CELL_INVOKE_PREDICTED:
3726 handleInvokePredictedChainingCell(cUnit);
3727 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003728 case CHAINING_CELL_HOT:
3729 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003730 blockList[blockId]->startOffset);
3731 break;
Jeff Hao97319a82009-08-12 16:57:15 -07003732#if defined(WITH_SELF_VERIFICATION)
3733 case CHAINING_CELL_BACKWARD_BRANCH:
3734 handleBackwardBranchChainingCell(cUnit,
3735 blockList[blockId]->startOffset);
3736 break;
3737#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003738 default:
3739 dvmAbort();
3740 break;
3741 }
3742 }
3743 }
Ben Chenge9695e52009-06-16 16:11:47 -07003744
3745 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003746}
3747
3748/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07003749bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003750{
Bill Buzbee716f1202009-07-23 13:22:09 -07003751 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003752
3753 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07003754 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003755 }
3756
3757 switch (work->kind) {
3758 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07003759 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003760 break;
3761 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003762 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07003763 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003764 break;
3765 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07003766 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003767 dvmAbort();
3768 }
3769 return res;
3770}
3771
Ben Chengba4fc8b2009-06-01 13:00:29 -07003772/* Architectural-specific debugging helpers go here */
3773void dvmCompilerArchDump(void)
3774{
3775 /* Print compiled opcode in this VM instance */
3776 int i, start, streak;
3777 char buf[1024];
3778
3779 streak = i = 0;
3780 buf[0] = 0;
3781 while (opcodeCoverage[i] == 0 && i < 256) {
3782 i++;
3783 }
3784 if (i == 256) {
3785 return;
3786 }
3787 for (start = i++, streak = 1; i < 256; i++) {
3788 if (opcodeCoverage[i]) {
3789 streak++;
3790 } else {
3791 if (streak == 1) {
3792 sprintf(buf+strlen(buf), "%x,", start);
3793 } else {
3794 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3795 }
3796 streak = 0;
3797 while (opcodeCoverage[i] == 0 && i < 256) {
3798 i++;
3799 }
3800 if (i < 256) {
3801 streak = 1;
3802 start = i;
3803 }
3804 }
3805 }
3806 if (streak) {
3807 if (streak == 1) {
3808 sprintf(buf+strlen(buf), "%x", start);
3809 } else {
3810 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3811 }
3812 }
3813 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07003814 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003815 }
3816}