blob: ff6a3a6f638f249a32495d201ff4329c08ee0449 [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/*
551 * The following are building blocks to insert constants into the pool or
552 * instruction streams.
553 */
554
555/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700556static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700557{
558 /* Add the constant to the literal pool */
559 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700560 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700561 newValue->operands[0] = value;
562 newValue->generic.next = cUnit->wordList;
563 cUnit->wordList = (LIR *) newValue;
564 return newValue;
565 } else {
566 /* Add the constant in the middle of code stream */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700567 newLIR1(cUnit, ARM_16BIT_DATA, (value & 0xffff));
568 newLIR1(cUnit, ARM_16BIT_DATA, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700569 }
570 return NULL;
571}
572
573/*
574 * Search the existing constants in the literal pool for an exact or close match
575 * within specified delta (greater or equal to 0).
576 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700577static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700578 unsigned int delta)
579{
580 LIR *dataTarget = cUnit->wordList;
581 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700582 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700583 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700584 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700585 dataTarget = dataTarget->next;
586 }
587 return NULL;
588}
589
Ben Chengba4fc8b2009-06-01 13:00:29 -0700590/* Perform the actual operation for OP_RETURN_* */
591static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
592{
593 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
594#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -0700595 gDvmJit.returnOp++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700596#endif
597 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee9bc3df32009-07-30 10:52:29 -0700598 /* Insert branch, but defer setting of target */
599 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700600 /* Set up the place holder to reconstruct this Dalvik PC */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700601 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
602 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700603 pcrLabel->operands[0] = dPC;
604 pcrLabel->operands[1] = mir->offset;
605 /* Insert the place holder to the growable list */
606 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
607 /* Branch to the PC reconstruction code */
608 branch->generic.target = (LIR *) pcrLabel;
609}
610
Ben Chengba4fc8b2009-06-01 13:00:29 -0700611/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700612static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
613 ArmLIR *branch,
614 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700615{
616 /* Set up the place holder to reconstruct this Dalvik PC */
617 if (pcrLabel == NULL) {
618 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700619 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
620 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700621 pcrLabel->operands[0] = dPC;
622 pcrLabel->operands[1] = dOffset;
623 /* Insert the place holder to the growable list */
624 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
625 }
626 /* Branch to the PC reconstruction code */
627 branch->generic.target = (LIR *) pcrLabel;
628 return pcrLabel;
629}
630
Ben Chengba4fc8b2009-06-01 13:00:29 -0700631
632/*
633 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
634 * satisfies.
635 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700636static inline ArmLIR *insertRegRegCheck(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700637 ArmConditionCode cond,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700638 int reg1, int reg2, int dOffset,
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700639 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700640{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700641 ArmLIR *res;
642 res = opRegReg(cUnit, OP_CMP, reg1, reg2);
643 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
644 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
645 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700646}
647
Ben Chenge9695e52009-06-16 16:11:47 -0700648/*
649 * Perform null-check on a register. vReg is the Dalvik register being checked,
650 * and mReg is the machine register holding the actual value. If internal state
651 * indicates that vReg has been checked before the check request is ignored.
652 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700653static ArmLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
654 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700655{
Ben Chenge9695e52009-06-16 16:11:47 -0700656 /* This particular Dalvik register has been null-checked */
657 if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
658 return pcrLabel;
659 }
660 dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
661 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
662}
663
664/*
665 * Perform zero-check on a register. Similar to genNullCheck but the value being
666 * checked does not have a corresponding Dalvik register.
667 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700668static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
669 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -0700670{
671 return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700672}
673
674/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700675static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
676 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700677{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700678 return insertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700679 pcrLabel);
680}
681
682/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700683static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
684 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700685{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700686 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700687 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
688}
689
690/* Load a wide field from an object instance */
691static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
692{
693 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700694 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700695
Ben Chenge9695e52009-06-16 16:11:47 -0700696 /* Allocate reg0..reg3 into physical registers r0..r3 */
697
698 /* See if vB is in a native register. If so, reuse it. */
699 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
700 /* Ping reg3 to the other register of the same pair containing reg2 */
701 reg3 = reg2 ^ 0x1;
702 /*
703 * Ping reg0 to the first register of the alternate register pair
704 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700705 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700706 reg1 = NEXT_REG(reg0);
707
708 loadValue(cUnit, dInsn->vB, reg2);
709 loadConstant(cUnit, reg3, fieldOffset);
710 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700711 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700712#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700713 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700714#else
715 int regMap = reg1 << 8 | reg0 << 4 | reg2;
716 selfVerificationMemOpWrapper(cUnit, regMap,
717 &selfVerificationLoadDoubleword);
Jeff Hao97319a82009-08-12 16:57:15 -0700718#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700719 storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700720}
721
722/* Store a wide field to an object instance */
723static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
724{
725 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700726 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700727
Ben Chenge9695e52009-06-16 16:11:47 -0700728 /* Allocate reg0..reg3 into physical registers r0..r3 */
729
730 /* See if vB is in a native register. If so, reuse it. */
731 reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
732 /* Ping reg3 to the other register of the same pair containing reg2 */
733 reg3 = reg2 ^ 0x1;
734 /*
735 * Ping reg0 to the first register of the alternate register pair
736 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700737 reg0 = (reg2 + 2) & 0xa;
Ben Chenge9695e52009-06-16 16:11:47 -0700738 reg1 = NEXT_REG(reg0);
739
740
741 loadValue(cUnit, dInsn->vB, reg2);
742 loadValuePair(cUnit, dInsn->vA, reg0, reg1);
743 updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
744 loadConstant(cUnit, reg3, fieldOffset);
745 genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700746 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700747#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700748 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -0700749#else
750 int regMap = reg1 << 8 | reg0 << 4 | reg2;
751 selfVerificationMemOpWrapper(cUnit, regMap,
752 &selfVerificationStoreDoubleword);
753#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700754}
755
756/*
757 * Load a field from an object instance
758 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700759 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700760static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700761 int fieldOffset)
762{
763 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700764 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700765
Ben Chenge9695e52009-06-16 16:11:47 -0700766 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
767 reg1 = NEXT_REG(reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700768 loadValue(cUnit, dInsn->vB, reg0);
Jeff Hao97319a82009-08-12 16:57:15 -0700769#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700770 loadBaseDisp(cUnit, mir, reg0, fieldOffset, reg1, size, true, dInsn->vB);
Jeff Hao97319a82009-08-12 16:57:15 -0700771#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700772 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700773 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700774 loadConstant(cUnit, reg1, fieldOffset);
775 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700776
Bill Buzbee270c1d62009-08-13 16:58:07 -0700777 int regMap = reg1 << 4 | reg0;
Jeff Hao97319a82009-08-12 16:57:15 -0700778 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
Jeff Hao97319a82009-08-12 16:57:15 -0700779#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -0700780 storeValue(cUnit, reg1, dInsn->vA, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700781}
782
783/*
784 * Store a field to an object instance
785 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700786 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700787static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700788 int fieldOffset)
789{
790 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Chenge9695e52009-06-16 16:11:47 -0700791 int reg0, reg1, reg2;
792
793 reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
794 reg1 = NEXT_REG(reg0);
795 reg2 = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700796
Ben Chenge9695e52009-06-16 16:11:47 -0700797 loadValue(cUnit, dInsn->vB, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -0700798 loadValue(cUnit, dInsn->vA, reg2);
799 updateLiveRegister(cUnit, dInsn->vA, reg2);
800 genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -0700801#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700802 storeBaseDisp(cUnit, reg0, fieldOffset, reg2, size, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700803#else
804 /* Combine address and offset */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700805 loadConstant(cUnit, reg1, fieldOffset);
806 opRegReg(cUnit, OP_ADD, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700807
808 int regMap = reg2 << 4 | reg0;
809 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
810
Bill Buzbee270c1d62009-08-13 16:58:07 -0700811 opRegReg(cUnit, OP_SUB, reg0, reg1);
Jeff Hao97319a82009-08-12 16:57:15 -0700812#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700813}
814
815
Ben Chengba4fc8b2009-06-01 13:00:29 -0700816/*
817 * Generate array load
818 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700819 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700820static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700821 int vArray, int vIndex, int vDest, int scale)
822{
823 int lenOffset = offsetof(ArrayObject, length);
824 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700825 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700826
Ben Chenge9695e52009-06-16 16:11:47 -0700827 reg0 = selectFirstRegister(cUnit, vArray, false);
828 reg1 = NEXT_REG(reg0);
829 reg2 = NEXT_REG(reg1);
830 reg3 = NEXT_REG(reg2);
831
832 loadValue(cUnit, vArray, reg2);
833 loadValue(cUnit, vIndex, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700834
835 /* null object? */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700836 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset, NULL);
837 loadWordDisp(cUnit, reg2, lenOffset, reg0); /* Get len */
838 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone); /* reg2 -> array data */
Ben Chenge9695e52009-06-16 16:11:47 -0700839 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
Jeff Hao97319a82009-08-12 16:57:15 -0700840#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -0700841 if ((size == LONG) || (size == DOUBLE)) {
842 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
843 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
844 loadBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
845 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
846 loadBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
Ben Chenge9695e52009-06-16 16:11:47 -0700847 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700848 } else {
Bill Buzbee270c1d62009-08-13 16:58:07 -0700849 loadBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
Ben Chenge9695e52009-06-16 16:11:47 -0700850 storeValue(cUnit, reg0, vDest, reg3);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700851 }
Jeff Hao97319a82009-08-12 16:57:15 -0700852#else
Bill Buzbee270c1d62009-08-13 16:58:07 -0700853 //TODO: probably want to move this into loadBaseIndexed
854 void *funct = NULL;
855 switch(size) {
856 case LONG:
857 case DOUBLE:
Jeff Hao97319a82009-08-12 16:57:15 -0700858 funct = (void*) &selfVerificationLoadDoubleword;
859 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700860 case WORD:
Jeff Hao97319a82009-08-12 16:57:15 -0700861 funct = (void*) &selfVerificationLoad;
862 break;
Bill Buzbee270c1d62009-08-13 16:58:07 -0700863 case UNSIGNED_HALF:
864 funct = (void*) &selfVerificationLoadHalfword;
865 break;
866 case SIGNED_HALF:
867 funct = (void*) &selfVerificationLoadSignedHalfword;
868 break;
869 case UNSIGNED_BYTE:
870 funct = (void*) &selfVerificationLoadByte;
871 break;
872 case SIGNED_BYTE:
873 funct = (void*) &selfVerificationLoadSignedByte;
874 break;
875 default:
876 assert(0);
877 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -0700878 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700879 /* Combine address and index */
880 if (scale)
881 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
882 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700883
884 int regMap = reg1 << 8 | reg0 << 4 | reg2;
885 selfVerificationMemOpWrapper(cUnit, regMap, funct);
886
Bill Buzbee270c1d62009-08-13 16:58:07 -0700887 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700888
Bill Buzbee270c1d62009-08-13 16:58:07 -0700889 if ((size == LONG) || (size == DOUBLE))
Jeff Hao97319a82009-08-12 16:57:15 -0700890 storeValuePair(cUnit, reg0, reg1, vDest, reg3);
891 else
892 storeValue(cUnit, reg0, vDest, reg3);
893#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700894}
895
Ben Chengba4fc8b2009-06-01 13:00:29 -0700896/*
897 * Generate array store
898 *
Ben Chengba4fc8b2009-06-01 13:00:29 -0700899 */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700900static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700901 int vArray, int vIndex, int vSrc, int scale)
902{
903 int lenOffset = offsetof(ArrayObject, length);
904 int dataOffset = offsetof(ArrayObject, contents);
Ben Chenge9695e52009-06-16 16:11:47 -0700905 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700906
Ben Chenge9695e52009-06-16 16:11:47 -0700907 reg0 = selectFirstRegister(cUnit, vArray, false);
908 reg1 = NEXT_REG(reg0);
909 reg2 = NEXT_REG(reg1);
910 reg3 = NEXT_REG(reg2);
911
912 loadValue(cUnit, vArray, reg2);
913 loadValue(cUnit, vIndex, reg3);
914
Ben Cheng1efc9c52009-06-08 18:25:27 -0700915 /* null object? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700916 ArmLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
Ben Chenge9695e52009-06-16 16:11:47 -0700917 NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700918 loadWordDisp(cUnit, reg2, lenOffset, reg0); /* Get len */
919 opRegImm(cUnit, OP_ADD, reg2, dataOffset, rNone); /* reg2 -> array data */
Ben Chenge9695e52009-06-16 16:11:47 -0700920 genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
921 /* at this point, reg2 points to array, reg3 is unscaled index */
Bill Buzbee270c1d62009-08-13 16:58:07 -0700922#if !defined(WITH_SELF_VERIFICATION)
923 if ((size == LONG) || (size == DOUBLE)) {
924 //TUNING: redo. Make specific wide routine, perhaps use ldmia/fp regs
925 loadValuePair(cUnit, vSrc, reg0, reg1);
926 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
927 if (scale)
928 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
929 storeBaseIndexed(cUnit, reg2, reg3, reg0, 0, WORD);
930 opRegImm(cUnit, OP_ADD, reg2, 4, rNone);
931 storeBaseIndexed(cUnit, reg2, reg3, reg1, 0, WORD);
932 } else {
933 loadValue(cUnit, vSrc, reg0);
934 updateLiveRegister(cUnit, vSrc, reg0);
935 storeBaseIndexed(cUnit, reg2, reg3, reg0, scale, size);
936 }
937#else
938 //TODO: probably want to move this into storeBaseIndexed
939 void *funct = NULL;
940 switch(size) {
941 case LONG:
942 case DOUBLE:
943 funct = (void*) &selfVerificationStoreDoubleword;
944 break;
945 case WORD:
946 funct = (void*) &selfVerificationStore;
947 break;
948 case SIGNED_HALF:
949 case UNSIGNED_HALF:
950 funct = (void*) &selfVerificationStoreHalfword;
951 break;
952 case SIGNED_BYTE:
953 case UNSIGNED_BYTE:
954 funct = (void*) &selfVerificationStoreByte;
955 break;
956 default:
957 assert(0);
958 dvmAbort();
959 }
960
961 /* Combine address and index */
962 if ((size == LONG) || (size == DOUBLE)) {
Ben Chenge9695e52009-06-16 16:11:47 -0700963 loadValuePair(cUnit, vSrc, reg0, reg1);
964 updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700965 } else {
Ben Chenge9695e52009-06-16 16:11:47 -0700966 loadValue(cUnit, vSrc, reg0);
967 updateLiveRegister(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700968 }
Bill Buzbee270c1d62009-08-13 16:58:07 -0700969 if (scale)
970 opRegRegImm(cUnit, OP_LSL, reg3, reg3, scale, rNone);
971 opRegReg(cUnit, OP_ADD, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700972
973 int regMap = reg1 << 8 | reg0 << 4 | reg2;
974 selfVerificationMemOpWrapper(cUnit, regMap, funct);
975
Bill Buzbee270c1d62009-08-13 16:58:07 -0700976 opRegReg(cUnit, OP_SUB, reg2, reg3);
Jeff Hao97319a82009-08-12 16:57:15 -0700977#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700978}
979
980static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
981 int vSrc1, int vShift)
982{
Ben Chenge9695e52009-06-16 16:11:47 -0700983 /*
984 * Don't mess with the regsiters here as there is a particular calling
985 * convention to the out-of-line handler.
986 */
987 loadValue(cUnit, vShift, r2);
988 loadValuePair(cUnit, vSrc1, r0, r1);
989 switch( mir->dalvikInsn.opCode) {
990 case OP_SHL_LONG:
991 case OP_SHL_LONG_2ADDR:
992 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
993 break;
994 case OP_SHR_LONG:
995 case OP_SHR_LONG_2ADDR:
996 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
997 break;
998 case OP_USHR_LONG:
999 case OP_USHR_LONG_2ADDR:
1000 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1001 break;
1002 default:
1003 return true;
1004 }
1005 storeValuePair(cUnit, r0, r1, vDest, r2);
1006 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001007}
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001008bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1009 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001010{
Ben Chenge9695e52009-06-16 16:11:47 -07001011 /*
1012 * Don't optimize the regsiter usage here as they are governed by the EABI
1013 * calling convention.
1014 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001015 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001016 int reg0, reg1;
1017
Ben Chengba4fc8b2009-06-01 13:00:29 -07001018 /* TODO: use a proper include file to define these */
1019 float __aeabi_fadd(float a, float b);
1020 float __aeabi_fsub(float a, float b);
1021 float __aeabi_fdiv(float a, float b);
1022 float __aeabi_fmul(float a, float b);
1023 float fmodf(float a, float b);
1024
Ben Chenge9695e52009-06-16 16:11:47 -07001025 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1026 reg1 = NEXT_REG(reg0);
1027
Ben Chengba4fc8b2009-06-01 13:00:29 -07001028 switch (mir->dalvikInsn.opCode) {
1029 case OP_ADD_FLOAT_2ADDR:
1030 case OP_ADD_FLOAT:
1031 funct = (void*) __aeabi_fadd;
1032 break;
1033 case OP_SUB_FLOAT_2ADDR:
1034 case OP_SUB_FLOAT:
1035 funct = (void*) __aeabi_fsub;
1036 break;
1037 case OP_DIV_FLOAT_2ADDR:
1038 case OP_DIV_FLOAT:
1039 funct = (void*) __aeabi_fdiv;
1040 break;
1041 case OP_MUL_FLOAT_2ADDR:
1042 case OP_MUL_FLOAT:
1043 funct = (void*) __aeabi_fmul;
1044 break;
1045 case OP_REM_FLOAT_2ADDR:
1046 case OP_REM_FLOAT:
1047 funct = (void*) fmodf;
1048 break;
1049 case OP_NEG_FLOAT: {
Ben Chenge9695e52009-06-16 16:11:47 -07001050 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001051 opRegImm(cUnit, OP_ADD, reg0, 0x80000000, reg1);
Ben Chenge9695e52009-06-16 16:11:47 -07001052 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001053 return false;
1054 }
1055 default:
1056 return true;
1057 }
1058 loadConstant(cUnit, r2, (int)funct);
1059 loadValue(cUnit, vSrc1, r0);
1060 loadValue(cUnit, vSrc2, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001061 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001062 storeValue(cUnit, r0, vDest, r1);
1063 return false;
1064}
1065
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001066bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1067 int vDest, int vSrc1, int vSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001068{
1069 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001070 int reg0, reg1, reg2;
1071
Ben Chengba4fc8b2009-06-01 13:00:29 -07001072 /* TODO: use a proper include file to define these */
1073 double __aeabi_dadd(double a, double b);
1074 double __aeabi_dsub(double a, double b);
1075 double __aeabi_ddiv(double a, double b);
1076 double __aeabi_dmul(double a, double b);
1077 double fmod(double a, double b);
1078
Ben Chenge9695e52009-06-16 16:11:47 -07001079 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1080 reg1 = NEXT_REG(reg0);
1081 reg2 = NEXT_REG(reg1);
1082
Ben Chengba4fc8b2009-06-01 13:00:29 -07001083 switch (mir->dalvikInsn.opCode) {
1084 case OP_ADD_DOUBLE_2ADDR:
1085 case OP_ADD_DOUBLE:
1086 funct = (void*) __aeabi_dadd;
1087 break;
1088 case OP_SUB_DOUBLE_2ADDR:
1089 case OP_SUB_DOUBLE:
1090 funct = (void*) __aeabi_dsub;
1091 break;
1092 case OP_DIV_DOUBLE_2ADDR:
1093 case OP_DIV_DOUBLE:
1094 funct = (void*) __aeabi_ddiv;
1095 break;
1096 case OP_MUL_DOUBLE_2ADDR:
1097 case OP_MUL_DOUBLE:
1098 funct = (void*) __aeabi_dmul;
1099 break;
1100 case OP_REM_DOUBLE_2ADDR:
1101 case OP_REM_DOUBLE:
1102 funct = (void*) fmod;
1103 break;
1104 case OP_NEG_DOUBLE: {
Ben Chenge9695e52009-06-16 16:11:47 -07001105 loadValuePair(cUnit, vSrc2, reg0, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001106 opRegImm(cUnit, OP_ADD, reg1, 0x80000000, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001107 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001108 return false;
1109 }
1110 default:
1111 return true;
1112 }
Ben Chenge9695e52009-06-16 16:11:47 -07001113 /*
1114 * Don't optimize the regsiter usage here as they are governed by the EABI
1115 * calling convention.
1116 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001117 loadConstant(cUnit, r4PC, (int)funct);
1118 loadValuePair(cUnit, vSrc1, r0, r1);
1119 loadValuePair(cUnit, vSrc2, r2, r3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001120 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001121 storeValuePair(cUnit, r0, r1, vDest, r2);
1122 return false;
1123}
1124
1125static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
1126 int vSrc1, int vSrc2)
1127{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001128 OpKind firstOp = OP_BKPT;
1129 OpKind secondOp = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001130 bool callOut = false;
1131 void *callTgt;
1132 int retReg = r0;
Ben Chenge9695e52009-06-16 16:11:47 -07001133 int reg0, reg1, reg2, reg3;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001134 /* TODO - find proper .h file to declare these */
1135 long long __aeabi_ldivmod(long long op1, long long op2);
1136
1137 switch (mir->dalvikInsn.opCode) {
1138 case OP_NOT_LONG:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001139 firstOp = OP_MVN;
1140 secondOp = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001141 break;
1142 case OP_ADD_LONG:
1143 case OP_ADD_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001144 firstOp = OP_ADD;
1145 secondOp = OP_ADC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001146 break;
1147 case OP_SUB_LONG:
1148 case OP_SUB_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001149 firstOp = OP_SUB;
1150 secondOp = OP_SBC;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001151 break;
1152 case OP_MUL_LONG:
1153 case OP_MUL_LONG_2ADDR:
1154 loadValuePair(cUnit, vSrc1, r0, r1);
1155 loadValuePair(cUnit, vSrc2, r2, r3);
1156 genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
1157 storeValuePair(cUnit, r0, r1, vDest, r2);
1158 return false;
1159 break;
1160 case OP_DIV_LONG:
1161 case OP_DIV_LONG_2ADDR:
1162 callOut = true;
1163 retReg = r0;
1164 callTgt = (void*)__aeabi_ldivmod;
1165 break;
1166 /* NOTE - result is in r2/r3 instead of r0/r1 */
1167 case OP_REM_LONG:
1168 case OP_REM_LONG_2ADDR:
1169 callOut = true;
1170 callTgt = (void*)__aeabi_ldivmod;
1171 retReg = r2;
1172 break;
1173 case OP_AND_LONG:
1174 case OP_AND_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001175 firstOp = OP_AND;
1176 secondOp = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001177 break;
1178 case OP_OR_LONG:
1179 case OP_OR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001180 firstOp = OP_OR;
1181 secondOp = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001182 break;
1183 case OP_XOR_LONG:
1184 case OP_XOR_LONG_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001185 firstOp = OP_XOR;
1186 secondOp = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001187 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001188 case OP_NEG_LONG: {
1189 reg0 = selectFirstRegister(cUnit, vSrc2, true);
1190 reg1 = NEXT_REG(reg0);
1191 reg2 = NEXT_REG(reg1);
1192 reg3 = NEXT_REG(reg2);
1193
1194 loadValuePair(cUnit, vSrc2, reg0, reg1);
1195 loadConstant(cUnit, reg3, 0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001196 opRegRegReg(cUnit, OP_SUB, reg2, reg3, reg0);
1197 opRegReg(cUnit, OP_SBC, reg3, reg1);
Ben Cheng38329f52009-07-07 14:19:20 -07001198 storeValuePair(cUnit, reg2, reg3, vDest, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001199 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001200 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001201 default:
1202 LOGE("Invalid long arith op");
1203 dvmAbort();
1204 }
1205 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001206 reg0 = selectFirstRegister(cUnit, vSrc1, true);
1207 reg1 = NEXT_REG(reg0);
1208 reg2 = NEXT_REG(reg1);
1209 reg3 = NEXT_REG(reg2);
1210
1211 loadValuePair(cUnit, vSrc1, reg0, reg1);
1212 loadValuePair(cUnit, vSrc2, reg2, reg3);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001213 opRegReg(cUnit, firstOp, reg0, reg2);
1214 opRegReg(cUnit, secondOp, reg1, reg3);
1215 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chenge9695e52009-06-16 16:11:47 -07001216 /*
Bill Buzbee270c1d62009-08-13 16:58:07 -07001217 * Don't optimize the register usage here as they are governed by the EABI
Ben Chenge9695e52009-06-16 16:11:47 -07001218 * calling convention.
1219 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001220 } else {
1221 loadValuePair(cUnit, vSrc2, r2, r3);
1222 loadConstant(cUnit, r4PC, (int) callTgt);
1223 loadValuePair(cUnit, vSrc1, r0, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001224 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001225 storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
1226 }
1227 return false;
1228}
1229
1230static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
1231 int vSrc1, int vSrc2)
1232{
Bill Buzbee270c1d62009-08-13 16:58:07 -07001233 OpKind op = OP_BKPT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001234 bool callOut = false;
1235 bool checkZero = false;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001236 bool threeOperand = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001237 int retReg = r0;
1238 void *callTgt;
Ben Chenge9695e52009-06-16 16:11:47 -07001239 int reg0, reg1, regDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001240
1241 /* TODO - find proper .h file to declare these */
1242 int __aeabi_idivmod(int op1, int op2);
1243 int __aeabi_idiv(int op1, int op2);
1244
1245 switch (mir->dalvikInsn.opCode) {
1246 case OP_NEG_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001247 op = OP_NEG;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001248 break;
1249 case OP_NOT_INT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001250 op = OP_MVN;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001251 break;
1252 case OP_ADD_INT:
1253 case OP_ADD_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001254 op = OP_ADD;
1255 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001256 break;
1257 case OP_SUB_INT:
1258 case OP_SUB_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001259 op = OP_SUB;
1260 threeOperand = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001261 break;
1262 case OP_MUL_INT:
1263 case OP_MUL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001264 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001265 break;
1266 case OP_DIV_INT:
1267 case OP_DIV_INT_2ADDR:
1268 callOut = true;
1269 checkZero = true;
1270 callTgt = __aeabi_idiv;
1271 retReg = r0;
1272 break;
1273 /* NOTE: returns in r1 */
1274 case OP_REM_INT:
1275 case OP_REM_INT_2ADDR:
1276 callOut = true;
1277 checkZero = true;
1278 callTgt = __aeabi_idivmod;
1279 retReg = r1;
1280 break;
1281 case OP_AND_INT:
1282 case OP_AND_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001283 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001284 break;
1285 case OP_OR_INT:
1286 case OP_OR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001287 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001288 break;
1289 case OP_XOR_INT:
1290 case OP_XOR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001291 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001292 break;
1293 case OP_SHL_INT:
1294 case OP_SHL_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001295 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001296 break;
1297 case OP_SHR_INT:
1298 case OP_SHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001299 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001300 break;
1301 case OP_USHR_INT:
1302 case OP_USHR_INT_2ADDR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001303 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001304 break;
1305 default:
1306 LOGE("Invalid word arith op: 0x%x(%d)",
1307 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1308 dvmAbort();
1309 }
1310 if (!callOut) {
Ben Chenge9695e52009-06-16 16:11:47 -07001311 /* Try to allocate reg0 to the currently cached source operand */
1312 if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
1313 reg0 = selectFirstRegister(cUnit, vSrc1, false);
1314 reg1 = NEXT_REG(reg0);
1315 regDest = NEXT_REG(reg1);
1316
1317 loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
1318 loadValue(cUnit, vSrc2, reg1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001319 if (threeOperand) {
1320 opRegRegReg(cUnit, op, regDest, reg0, reg1);
1321 storeValue(cUnit, regDest, vDest, reg1);
1322 } else {
1323 opRegReg(cUnit, op, reg0, reg1);
1324 storeValue(cUnit, reg0, vDest, reg1);
1325 }
Ben Chenge9695e52009-06-16 16:11:47 -07001326 } else {
1327 reg0 = selectFirstRegister(cUnit, vSrc2, false);
1328 reg1 = NEXT_REG(reg0);
1329 regDest = NEXT_REG(reg1);
1330
1331 loadValue(cUnit, vSrc1, reg1); /* Load this value first */
1332 loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001333 if (threeOperand) {
1334 opRegRegReg(cUnit, op, regDest, reg1, reg0);
1335 storeValue(cUnit, regDest, vDest, reg1);
1336 } else {
1337 opRegReg(cUnit, op, reg1, reg0);
1338 storeValue(cUnit, reg1, vDest, reg0);
1339 }
Ben Chenge9695e52009-06-16 16:11:47 -07001340 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001341 } else {
Ben Chenge9695e52009-06-16 16:11:47 -07001342 /*
1343 * Load the callout target first since it will never be eliminated
1344 * and its value will be used first.
1345 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001346 loadConstant(cUnit, r2, (int) callTgt);
Ben Chenge9695e52009-06-16 16:11:47 -07001347 /*
1348 * Load vSrc2 first if it is not cached in a native register or it
1349 * is in r0 which will be clobbered if vSrc1 is loaded first.
1350 */
1351 if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
1352 cUnit->registerScoreboard.nativeReg == r0) {
1353 /* Cannot be optimized and won't clobber r0 */
1354 loadValue(cUnit, vSrc2, r1);
1355 /* May be optimized if vSrc1 is cached */
1356 loadValue(cUnit, vSrc1, r0);
1357 } else {
1358 loadValue(cUnit, vSrc1, r0);
1359 loadValue(cUnit, vSrc2, r1);
1360 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001361 if (checkZero) {
Ben Chenge9695e52009-06-16 16:11:47 -07001362 genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001363 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001364 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001365 storeValue(cUnit, retReg, vDest, r2);
1366 }
1367 return false;
1368}
1369
1370static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
1371{
1372 OpCode opCode = mir->dalvikInsn.opCode;
1373 int vA = mir->dalvikInsn.vA;
1374 int vB = mir->dalvikInsn.vB;
1375 int vC = mir->dalvikInsn.vC;
1376
1377 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
1378 return genArithOpLong(cUnit,mir, vA, vA, vB);
1379 }
1380 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
1381 return genArithOpLong(cUnit,mir, vA, vB, vC);
1382 }
1383 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
1384 return genShiftOpLong(cUnit,mir, vA, vA, vB);
1385 }
1386 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
1387 return genShiftOpLong(cUnit,mir, vA, vB, vC);
1388 }
1389 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
1390 return genArithOpInt(cUnit,mir, vA, vA, vB);
1391 }
1392 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
1393 return genArithOpInt(cUnit,mir, vA, vB, vC);
1394 }
1395 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001396 return genArithOpFloat(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001397 }
1398 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001399 return genArithOpFloat(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001400 }
1401 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001402 return genArithOpDouble(cUnit,mir, vA, vA, vB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001403 }
1404 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07001405 return genArithOpDouble(cUnit,mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001406 }
1407 return true;
1408}
1409
Bill Buzbeed45ba372009-06-15 17:00:57 -07001410static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1411 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001412{
Ben Chenge9695e52009-06-16 16:11:47 -07001413 /*
1414 * Don't optimize the register usage since it calls out to template
1415 * functions
1416 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001417 loadConstant(cUnit, r2, (int)funct);
1418 if (srcSize == 1) {
1419 loadValue(cUnit, mir->dalvikInsn.vB, r0);
1420 } else {
1421 loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
1422 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001423 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001424 if (tgtSize == 1) {
1425 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
1426 } else {
1427 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
1428 }
1429 return false;
1430}
1431
Ben Chengba4fc8b2009-06-01 13:00:29 -07001432static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1433 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001434 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001435{
1436 unsigned int i;
1437 unsigned int regMask = 0;
1438
1439 /* Load arguments to r0..r4 */
1440 for (i = 0; i < dInsn->vA; i++) {
1441 regMask |= 1 << i;
1442 loadValue(cUnit, dInsn->arg[i], i);
1443 }
1444 if (regMask) {
1445 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001446 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1447 sizeof(StackSaveArea) + (dInsn->vA << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001448 /* generate null check */
1449 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001450 *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
1451 NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001452 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001453 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001454 }
1455}
1456
1457static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1458 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001459 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001460{
1461 int srcOffset = dInsn->vC << 2;
1462 int numArgs = dInsn->vA;
1463 int regMask;
1464 /*
1465 * r4PC : &rFP[vC]
1466 * r7: &newFP[0]
1467 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001468 opRegRegImm(cUnit, OP_ADD, r4PC, rFP, srcOffset, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001469 /* load [r0 .. min(numArgs,4)] */
1470 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001471 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001472
Bill Buzbee270c1d62009-08-13 16:58:07 -07001473 opRegRegImm(cUnit, OP_SUB, r7, rFP,
1474 sizeof(StackSaveArea) + (numArgs << 2), rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001475 /* generate null check */
1476 if (pcrLabel) {
Ben Chenge9695e52009-06-16 16:11:47 -07001477 *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001478 }
1479
1480 /*
1481 * Handle remaining 4n arguments:
1482 * store previously loaded 4 values and load the next 4 values
1483 */
1484 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001485 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001486 /*
1487 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001488 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001489 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001490 opImm(cUnit, OP_PUSH, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001491 /* No need to generate the loop structure if numArgs <= 11 */
1492 if (numArgs > 11) {
1493 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001494 loopLabel = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001495 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001496 storeMultiple(cUnit, r7, regMask);
1497 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001498 /* No need to generate the loop structure if numArgs <= 11 */
1499 if (numArgs > 11) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001500 opRegImm(cUnit, OP_SUB, rFP, 4, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001501 genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
1502 }
1503 }
1504
1505 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001506 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001507
1508 /* Generate the loop epilogue - don't use r0 */
1509 if ((numArgs > 4) && (numArgs % 4)) {
1510 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Bill Buzbee270c1d62009-08-13 16:58:07 -07001511 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001512 }
1513 if (numArgs >= 8)
Bill Buzbee270c1d62009-08-13 16:58:07 -07001514 opImm(cUnit, OP_POP, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001515
1516 /* Save the modulo 4 arguments */
1517 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001518 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001519 }
1520}
1521
Ben Cheng38329f52009-07-07 14:19:20 -07001522/*
1523 * Generate code to setup the call stack then jump to the chaining cell if it
1524 * is not a native method.
1525 */
1526static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001527 BasicBlock *bb, ArmLIR *labelList,
1528 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001529 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001530{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001531 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001532
1533 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001534 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001535 /* r4PC = dalvikCallsite */
1536 loadConstant(cUnit, r4PC,
1537 (int) (cUnit->method->insns + mir->offset));
1538 addrRetChain->generic.target = (LIR *) retChainingCell;
1539 /*
Ben Cheng38329f52009-07-07 14:19:20 -07001540 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001541 * r1 = &ChainingCell
1542 * r4PC = callsiteDPC
1543 */
1544 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07001545 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001546#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07001547 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001548#endif
1549 } else {
1550 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
1551#if defined(INVOKE_STATS)
1552 gDvmJit.invokeChain++;
1553#endif
Ben Cheng38329f52009-07-07 14:19:20 -07001554 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001555 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1556 }
1557 /* Handle exceptions using the interpreter */
1558 genTrap(cUnit, mir->offset, pcrLabel);
1559}
1560
Ben Cheng38329f52009-07-07 14:19:20 -07001561/*
1562 * Generate code to check the validity of a predicted chain and take actions
1563 * based on the result.
1564 *
1565 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
1566 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
1567 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
1568 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
1569 * 0x426a99b2 : blx_2 see above --+
1570 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
1571 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
1572 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
1573 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
1574 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
1575 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
1576 * 0x426a99c0 : blx r7 --+
1577 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
1578 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
1579 * 0x426a99c6 : blx_2 see above --+
1580 */
1581static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
1582 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001583 ArmLIR *retChainingCell,
1584 ArmLIR *predChainingCell,
1585 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07001586{
1587 /* "this" is already left in r0 by genProcessArgs* */
1588
1589 /* r4PC = dalvikCallsite */
1590 loadConstant(cUnit, r4PC,
1591 (int) (cUnit->method->insns + mir->offset));
1592
1593 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001594 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001595 addrRetChain->generic.target = (LIR *) retChainingCell;
1596
1597 /* r2 = &predictedChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001598 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, OP_ADD, r2, rpc, 0,
1599 rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001600 predictedChainingCell->generic.target = (LIR *) predChainingCell;
1601
1602 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
1603
1604 /* return through lr - jump to the chaining cell */
1605 genUnconditionalBranch(cUnit, predChainingCell);
1606
1607 /*
1608 * null-check on "this" may have been eliminated, but we still need a PC-
1609 * reconstruction label for stack overflow bailout.
1610 */
1611 if (pcrLabel == NULL) {
1612 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001613 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1614 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07001615 pcrLabel->operands[0] = dPC;
1616 pcrLabel->operands[1] = mir->offset;
1617 /* Insert the place holder to the growable list */
1618 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1619 }
1620
1621 /* return through lr+2 - punt to the interpreter */
1622 genUnconditionalBranch(cUnit, pcrLabel);
1623
1624 /*
1625 * return through lr+4 - fully resolve the callee method.
1626 * r1 <- count
1627 * r2 <- &predictedChainCell
1628 * r3 <- this->class
1629 * r4 <- dPC
1630 * r7 <- this->class->vtable
1631 */
1632
1633 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001634 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001635
1636 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001637 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001638
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001639 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001640 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07001641
Bill Buzbee270c1d62009-08-13 16:58:07 -07001642 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1643 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001644
1645 /*
1646 * r0 = calleeMethod
1647 * r2 = &predictedChainingCell
1648 * r3 = class
1649 *
1650 * &returnChainingCell has been loaded into r1 but is not needed
1651 * when patching the chaining cell and will be clobbered upon
1652 * returning so it will be reconstructed again.
1653 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001654 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001655
1656 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001657 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001658 addrRetChain->generic.target = (LIR *) retChainingCell;
1659
1660 bypassRechaining->generic.target = (LIR *) addrRetChain;
1661 /*
1662 * r0 = calleeMethod,
1663 * r1 = &ChainingCell,
1664 * r4PC = callsiteDPC,
1665 */
1666 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
1667#if defined(INVOKE_STATS)
1668 gDvmJit.invokePredictedChain++;
1669#endif
1670 /* Handle exceptions using the interpreter */
1671 genTrap(cUnit, mir->offset, pcrLabel);
1672}
1673
1674/*
1675 * Up calling this function, "this" is stored in r0. The actual class will be
1676 * chased down off r0 and the predicted one will be retrieved through
1677 * predictedChainingCell then a comparison is performed to see whether the
1678 * previously established chaining is still valid.
1679 *
1680 * The return LIR is a branch based on the comparison result. The actual branch
1681 * target will be setup in the caller.
1682 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001683static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
1684 ArmLIR *predChainingCell,
1685 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07001686 MIR *mir)
1687{
1688 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001689 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001690
1691 /*
1692 * r2 now contains predicted class. The starting offset of the
1693 * cached value is 4 bytes into the chaining cell.
1694 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001695 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001696 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07001697 getPredictedClass->generic.target = (LIR *) predChainingCell;
1698
1699 /*
1700 * r0 now contains predicted method. The starting offset of the
1701 * cached value is 8 bytes into the chaining cell.
1702 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001703 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001704 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07001705 getPredictedMethod->generic.target = (LIR *) predChainingCell;
1706
1707 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001708 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07001709 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07001710 getRechainingRequestCount->generic.target =
1711 (LIR *) predChainingCell;
1712
1713 /* r4PC = dalvikCallsite */
1714 loadConstant(cUnit, r4PC,
1715 (int) (cUnit->method->insns + mir->offset));
1716
1717 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001718 ArmLIR *addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07001719 addrRetChain->generic.target = (LIR *) retChainingCell;
1720
1721 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001722 opRegReg(cUnit, OP_CMP, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07001723
Bill Buzbee270c1d62009-08-13 16:58:07 -07001724 return opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_EQ);
Ben Cheng38329f52009-07-07 14:19:20 -07001725}
1726
Ben Chengba4fc8b2009-06-01 13:00:29 -07001727/* Geneate a branch to go back to the interpreter */
1728static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
1729{
1730 /* r0 = dalvik pc */
1731 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001732 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
1733 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
1734 jitToInterpEntries.dvmJitToInterpPunt), r1);
1735 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001736}
1737
1738/*
1739 * Attempt to single step one instruction using the interpreter and return
1740 * to the compiled code for the next Dalvik instruction
1741 */
1742static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
1743{
1744 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
1745 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
1746 kInstrCanThrow;
1747 if ((mir->next == NULL) || (flags & flagsToCheck)) {
1748 genPuntToInterp(cUnit, mir->offset);
1749 return;
1750 }
1751 int entryAddr = offsetof(InterpState,
1752 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001753 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001754 /* r0 = dalvik pc */
1755 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
1756 /* r1 = dalvik pc of following instruction */
1757 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07001758 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001759}
1760
Bill Buzbee270c1d62009-08-13 16:58:07 -07001761/* Generate conditional branch instructions */
1762static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1763 ArmConditionCode cond,
1764 ArmLIR *target)
1765{
1766 ArmLIR *branch = opImmImm(cUnit, OP_COND_BR, 0, cond);
1767 branch->generic.target = (LIR *) target;
1768 return branch;
1769}
Ben Chengba4fc8b2009-06-01 13:00:29 -07001770
Bill Buzbee270c1d62009-08-13 16:58:07 -07001771/* Generate unconditional branch instructions */
1772static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1773{
1774 ArmLIR *branch = opNone(cUnit, OP_UNCOND_BR);
1775 branch->generic.target = (LIR *) target;
1776 return branch;
1777}
1778
1779/* Load the address of a Dalvik register on the frame */
1780static ArmLIR *loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
1781{
1782 return opRegRegImm(cUnit, OP_ADD, rDest, rFP, vSrc*4, rNone);
1783}
1784
1785/* Load a single value from rFP[src] and store them into rDest */
1786static ArmLIR *loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
1787{
1788 return loadBaseDisp(cUnit, NULL, rFP, vSrc * 4, rDest, WORD, false, -1);
1789}
1790
1791/* Load a word at base + displacement. Displacement must be word multiple */
1792static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
1793 int rDest)
1794{
1795 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, WORD, false,
1796 -1);
1797}
1798
1799static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
1800 int displacement, int rSrc, int rScratch)
1801{
1802 return storeBaseDisp(cUnit, rBase, displacement, rSrc, WORD, rScratch);
1803}
1804
1805/* Store a value from rSrc to vDest */
1806static ArmLIR *storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
1807 int rScratch)
1808{
1809 killNullCheckedRegister(cUnit, vDest);
1810 updateLiveRegister(cUnit, vDest, rSrc);
1811 return storeBaseDisp(cUnit, rFP, vDest * 4, rSrc, WORD, rScratch);
1812}
1813/*
1814 * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
1815 * rDestHi
1816 */
1817static ArmLIR *loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
1818 int rDestHi)
1819{
1820 ArmLIR *res;
1821 /* Use reg + imm5*4 to load the values if possible */
1822 if (vSrc <= 30) {
1823 res = loadWordDisp(cUnit, rFP, vSrc*4, rDestLo);
1824 loadWordDisp(cUnit, rFP, (vSrc+1)*4, rDestHi);
1825 } else {
1826 assert(rDestLo < rDestHi);
1827 res = loadValueAddress(cUnit, vSrc, rDestLo);
1828 loadMultiple(cUnit, rDestLo, (1<<rDestLo) | (1<<rDestHi));
1829 }
1830 return res;
1831}
1832
1833/*
1834 * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
1835 * vDest+1
1836 */
1837static ArmLIR *storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
1838 int vDest, int rScratch)
1839{
1840 ArmLIR *res;
1841 killNullCheckedRegister(cUnit, vDest);
1842 killNullCheckedRegister(cUnit, vDest+1);
1843 updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
1844
1845 /* Use reg + imm5*4 to store the values if possible */
1846 if (vDest <= 30) {
1847 res = storeWordDisp(cUnit, rFP, vDest*4, rSrcLo, rScratch);
1848 storeWordDisp(cUnit, rFP, (vDest+1)*4, rSrcHi, rScratch);
1849 } else {
1850 assert(rSrcLo < rSrcHi);
1851 res = loadValueAddress(cUnit, vDest, rScratch);
1852 storeMultiple(cUnit, rScratch, (1<<rSrcLo) | (1 << rSrcHi));
1853 }
1854 return res;
1855}
1856
1857static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1858{
1859 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
1860 dvmCompilerAppendLIR(cUnit, (LIR*)res);
1861 return res;
1862}
1863
Ben Chengba4fc8b2009-06-01 13:00:29 -07001864/*
1865 * The following are the first-level codegen routines that analyze the format
1866 * of each bytecode then either dispatch special purpose codegen routines
1867 * or produce corresponding Thumb instructions directly.
1868 */
1869
1870static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001871 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001872{
1873 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
1874 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
1875 return false;
1876}
1877
1878static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
1879{
1880 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
1881 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
1882 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
1883 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1884 return true;
1885 }
1886 switch (dalvikOpCode) {
1887 case OP_RETURN_VOID:
1888 genReturnCommon(cUnit,mir);
1889 break;
1890 case OP_UNUSED_73:
1891 case OP_UNUSED_79:
1892 case OP_UNUSED_7A:
1893 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
1894 return true;
1895 case OP_NOP:
1896 break;
1897 default:
1898 return true;
1899 }
1900 return false;
1901}
1902
1903static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
1904{
Ben Chenge9695e52009-06-16 16:11:47 -07001905 int reg0, reg1, reg2;
1906
Ben Chengba4fc8b2009-06-01 13:00:29 -07001907 switch (mir->dalvikInsn.opCode) {
1908 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07001909 case OP_CONST_4: {
1910 /* Avoid using the previously used register */
1911 reg0 = selectFirstRegister(cUnit, vNone, false);
1912 reg1 = NEXT_REG(reg0);
1913 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
1914 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001915 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001916 }
1917 case OP_CONST_WIDE_32: {
1918 /* Avoid using the previously used register */
1919 reg0 = selectFirstRegister(cUnit, vNone, true);
1920 reg1 = NEXT_REG(reg0);
1921 reg2 = NEXT_REG(reg1);
1922 loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001923 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07001924 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001925 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001926 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001927 default:
1928 return true;
1929 }
1930 return false;
1931}
1932
1933static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
1934{
Ben Chenge9695e52009-06-16 16:11:47 -07001935 int reg0, reg1, reg2;
1936
1937 /* Avoid using the previously used register */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001938 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07001939 case OP_CONST_HIGH16: {
1940 reg0 = selectFirstRegister(cUnit, vNone, false);
1941 reg1 = NEXT_REG(reg0);
1942 loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
1943 storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001944 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001945 }
1946 case OP_CONST_WIDE_HIGH16: {
1947 reg0 = selectFirstRegister(cUnit, vNone, true);
1948 reg1 = NEXT_REG(reg0);
1949 reg2 = NEXT_REG(reg1);
1950 loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
1951 loadConstant(cUnit, reg0, 0);
1952 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001953 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001954 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001955 default:
1956 return true;
1957 }
1958 return false;
1959}
1960
1961static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
1962{
1963 /* For OP_THROW_VERIFICATION_ERROR */
1964 genInterpSingleStep(cUnit, mir);
1965 return false;
1966}
1967
1968static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
1969{
Ben Chenge9695e52009-06-16 16:11:47 -07001970 /* Native register to use if the interested value is vA */
1971 int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
1972 /* Native register to use if source is not from Dalvik registers */
1973 int regvNone = selectFirstRegister(cUnit, vNone, false);
1974 /* Similar to regvA but for 64-bit values */
1975 int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
1976 /* Similar to regvNone but for 64-bit values */
1977 int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
1978
Ben Chengba4fc8b2009-06-01 13:00:29 -07001979 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001980 case OP_CONST_STRING_JUMBO:
1981 case OP_CONST_STRING: {
1982 void *strPtr = (void*)
1983 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
1984 assert(strPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001985 loadConstant(cUnit, regvNone, (int) strPtr );
1986 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001987 break;
1988 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001989 case OP_CONST_CLASS: {
1990 void *classPtr = (void*)
1991 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
1992 assert(classPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07001993 loadConstant(cUnit, regvNone, (int) classPtr );
1994 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001995 break;
1996 }
1997 case OP_SGET_OBJECT:
1998 case OP_SGET_BOOLEAN:
1999 case OP_SGET_CHAR:
2000 case OP_SGET_BYTE:
2001 case OP_SGET_SHORT:
2002 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002003 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002004 void *fieldPtr = (void*)
2005 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2006 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002007 loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002008#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002009 loadWordDisp(cUnit, regvNone, 0, regvNone);
Jeff Hao97319a82009-08-12 16:57:15 -07002010#else
2011 int regMap = regvNone << 4 | regvNone;
2012 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2013
Jeff Hao97319a82009-08-12 16:57:15 -07002014#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002015 storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
Ben Chengba4fc8b2009-06-01 13:00:29 -07002016 break;
2017 }
2018 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002019 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002020 void *fieldPtr = (void*)
2021 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002022 int reg0, reg1, reg2;
2023
Ben Chengba4fc8b2009-06-01 13:00:29 -07002024 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002025 reg0 = regvNoneWide;
2026 reg1 = NEXT_REG(reg0);
2027 reg2 = NEXT_REG(reg1);
2028 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002029#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002030 loadMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002031#else
2032 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2033 selfVerificationMemOpWrapper(cUnit, regMap,
2034 &selfVerificationLoadDoubleword);
2035
Jeff Hao97319a82009-08-12 16:57:15 -07002036#endif
Bill Buzbee270c1d62009-08-13 16:58:07 -07002037 storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002038 break;
2039 }
2040 case OP_SPUT_OBJECT:
2041 case OP_SPUT_BOOLEAN:
2042 case OP_SPUT_CHAR:
2043 case OP_SPUT_BYTE:
2044 case OP_SPUT_SHORT:
2045 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002046 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002047 void *fieldPtr = (void*)
2048 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002049
Ben Chengba4fc8b2009-06-01 13:00:29 -07002050 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002051 loadValue(cUnit, mir->dalvikInsn.vA, regvA);
2052 updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
2053 loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002054#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002055 storeWordDisp(cUnit, NEXT_REG(regvA), 0 , regvA, -1);
Jeff Hao97319a82009-08-12 16:57:15 -07002056#else
2057 int regMap = regvA << 4 | NEXT_REG(regvA);
2058 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2059#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002060 break;
2061 }
2062 case OP_SPUT_WIDE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002063 int reg0, reg1, reg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002064 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002065 void *fieldPtr = (void*)
2066 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002067
Ben Chengba4fc8b2009-06-01 13:00:29 -07002068 assert(fieldPtr != NULL);
Ben Chenge9695e52009-06-16 16:11:47 -07002069 reg0 = regvAWide;
2070 reg1 = NEXT_REG(reg0);
2071 reg2 = NEXT_REG(reg1);
2072 loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2073 updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
2074 loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002075#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002076 storeMultiple(cUnit, reg2, (1<<reg0 | 1<<reg1));
Jeff Hao97319a82009-08-12 16:57:15 -07002077#else
2078 int regMap = reg1 << 8 | reg0 << 4 | reg2;
2079 selfVerificationMemOpWrapper(cUnit, regMap,
2080 &selfVerificationStoreDoubleword);
2081#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002082 break;
2083 }
2084 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002085 /*
2086 * Obey the calling convention and don't mess with the register
2087 * usage.
2088 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002089 ClassObject *classPtr = (void*)
2090 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2091 assert(classPtr != NULL);
2092 assert(classPtr->status & CLASS_INITIALIZED);
2093 if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
2094 /* It's going to throw, just let the interp. deal with it. */
2095 genInterpSingleStep(cUnit, mir);
2096 return false;
2097 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002098 loadConstant(cUnit, r4PC, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002099 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002100 genExportPC(cUnit, mir, r2, r3 );
2101 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002102 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002103 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002104 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2105 break;
2106 }
2107 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002108 /*
2109 * Obey the calling convention and don't mess with the register
2110 * usage.
2111 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002112 ClassObject *classPtr =
2113 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2114 loadConstant(cUnit, r1, (int) classPtr );
2115 loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002116 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* Null? */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002117 ArmLIR *branch1 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002118 opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002119 /* r0 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002120 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002121 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002122 opRegReg(cUnit, OP_CMP, r0, r1);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002123 ArmLIR *branch2 =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002124 opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2125 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002126 /* check cast failed - punt to the interpreter */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002127 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002128 /* check cast passed - branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002129 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002130 branch1->generic.target = (LIR *)target;
2131 branch2->generic.target = (LIR *)target;
2132 break;
2133 }
2134 default:
2135 return true;
2136 }
2137 return false;
2138}
2139
2140static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2141{
2142 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2143 switch (dalvikOpCode) {
2144 case OP_MOVE_EXCEPTION: {
2145 int offset = offsetof(InterpState, self);
2146 int exOffset = offsetof(Thread, exception);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002147 loadWordDisp(cUnit, rGLUE, offset, r1);
2148 loadWordDisp(cUnit, r1, exOffset, r0);
Ben Chenge9695e52009-06-16 16:11:47 -07002149 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002150 break;
2151 }
2152 case OP_MOVE_RESULT:
2153 case OP_MOVE_RESULT_OBJECT: {
2154 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002155 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002156 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2157 break;
2158 }
2159 case OP_MOVE_RESULT_WIDE: {
2160 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002161 loadWordDisp(cUnit, rGLUE, offset, r0);
2162 loadWordDisp(cUnit, rGLUE, offset+4, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002163 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
2164 break;
2165 }
2166 case OP_RETURN_WIDE: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002167 int vSrc = mir->dalvikInsn.vA;
2168 int reg0 = selectFirstRegister(cUnit, vSrc, true);
2169 int reg1 = NEXT_REG(reg0);
2170 int rScratch = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002171 int offset = offsetof(InterpState, retval);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002172 loadValuePair(cUnit, vSrc, reg0, reg1);
2173 storeWordDisp(cUnit, rGLUE, offset, reg0, rScratch);
2174 storeWordDisp(cUnit, rGLUE, offset + 4, reg1, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002175 genReturnCommon(cUnit,mir);
2176 break;
2177 }
2178 case OP_RETURN:
2179 case OP_RETURN_OBJECT: {
Bill Buzbee270c1d62009-08-13 16:58:07 -07002180 int vSrc = mir->dalvikInsn.vA;
2181 int reg0 = selectFirstRegister(cUnit, vSrc, false);
2182 int rScratch = NEXT_REG(reg0);
2183 loadValue(cUnit, vSrc, reg0);
2184 storeWordDisp(cUnit, rGLUE, offsetof(InterpState, retval),
2185 reg0, rScratch);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002186 genReturnCommon(cUnit,mir);
2187 break;
2188 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002189 case OP_MONITOR_ENTER:
2190 case OP_MONITOR_EXIT: {
2191 int offset = offsetof(InterpState, self);
2192 loadValue(cUnit, mir->dalvikInsn.vA, r1);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002193 loadWordDisp(cUnit, rGLUE, offset, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002194 if (dalvikOpCode == OP_MONITOR_ENTER) {
2195 loadConstant(cUnit, r2, (int)dvmLockObject);
2196 } else {
2197 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2198 }
Ben Chenge9695e52009-06-16 16:11:47 -07002199 genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002200 /* Do the call */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002201 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002202 break;
2203 }
2204 case OP_THROW: {
2205 genInterpSingleStep(cUnit, mir);
2206 break;
2207 }
2208 default:
2209 return true;
2210 }
2211 return false;
2212}
2213
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002214static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002215{
2216 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002217
Ben Chengba4fc8b2009-06-01 13:00:29 -07002218 float __aeabi_i2f( int op1 );
2219 int __aeabi_f2iz( float op1 );
2220 float __aeabi_d2f( double op1 );
2221 double __aeabi_f2d( float op1 );
2222 double __aeabi_i2d( int op1 );
2223 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002224 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002225 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002226 s8 dvmJitf2l( float op1 );
2227 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002228
Bill Buzbeed45ba372009-06-15 17:00:57 -07002229 switch (opCode) {
2230 case OP_INT_TO_FLOAT:
2231 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2232 case OP_FLOAT_TO_INT:
2233 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2234 case OP_DOUBLE_TO_FLOAT:
2235 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2236 case OP_FLOAT_TO_DOUBLE:
2237 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2238 case OP_INT_TO_DOUBLE:
2239 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2240 case OP_DOUBLE_TO_INT:
2241 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2242 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002243 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002244 case OP_LONG_TO_FLOAT:
2245 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2246 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002247 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002248 case OP_LONG_TO_DOUBLE:
2249 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2250 default:
2251 return true;
2252 }
2253 return false;
2254}
2255
2256static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2257{
2258 OpCode opCode = mir->dalvikInsn.opCode;
2259 int vSrc1Dest = mir->dalvikInsn.vA;
2260 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002261 int reg0, reg1, reg2;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002262
Ben Chengba4fc8b2009-06-01 13:00:29 -07002263 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
2264 return genArithOp( cUnit, mir );
2265 }
2266
Ben Chenge9695e52009-06-16 16:11:47 -07002267 /*
2268 * If data type is 64-bit, re-calculate the register numbers in the
2269 * corresponding cases.
2270 */
2271 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2272 reg1 = NEXT_REG(reg0);
2273 reg2 = NEXT_REG(reg1);
2274
Ben Chengba4fc8b2009-06-01 13:00:29 -07002275 switch (opCode) {
2276 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002277 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002278 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002279 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002280 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002281 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002282 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002283 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002284 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002285 case OP_LONG_TO_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002286 return genConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002287 case OP_NEG_INT:
2288 case OP_NOT_INT:
2289 return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
2290 case OP_NEG_LONG:
2291 case OP_NOT_LONG:
2292 return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
2293 case OP_NEG_FLOAT:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002294 return genArithOpFloat(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002295 case OP_NEG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002296 return genArithOpDouble(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
Ben Chenge9695e52009-06-16 16:11:47 -07002297 case OP_MOVE_WIDE: {
2298 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2299 reg1 = NEXT_REG(reg0);
2300 reg2 = NEXT_REG(reg1);
2301
2302 loadValuePair(cUnit, vSrc2, reg0, reg1);
2303 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002304 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002305 }
2306 case OP_INT_TO_LONG: {
2307 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2308 reg1 = NEXT_REG(reg0);
2309 reg2 = NEXT_REG(reg1);
2310
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002311 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002312 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chenge9695e52009-06-16 16:11:47 -07002313 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002314 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002315 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002316 case OP_MOVE:
2317 case OP_MOVE_OBJECT:
2318 case OP_LONG_TO_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002319 loadValue(cUnit, vSrc2, reg0);
2320 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002321 break;
2322 case OP_INT_TO_BYTE:
Ben Chenge9695e52009-06-16 16:11:47 -07002323 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002324 opRegReg(cUnit, OP_2BYTE, reg1, reg0);
2325 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002326 break;
2327 case OP_INT_TO_SHORT:
Ben Chenge9695e52009-06-16 16:11:47 -07002328 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002329 opRegReg(cUnit, OP_2SHORT, reg1, reg0);
2330 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002331 break;
2332 case OP_INT_TO_CHAR:
Ben Chenge9695e52009-06-16 16:11:47 -07002333 loadValue(cUnit, vSrc2, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002334 opRegReg(cUnit, OP_2CHAR, reg1, reg0);
2335 storeValue(cUnit, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002336 break;
2337 case OP_ARRAY_LENGTH: {
2338 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002339 loadValue(cUnit, vSrc2, reg1);
2340 genNullCheck(cUnit, vSrc2, reg1, mir->offset, NULL);
2341 loadWordDisp(cUnit, reg1, lenOffset, reg0);
Ben Chenge9695e52009-06-16 16:11:47 -07002342 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002343 break;
2344 }
2345 default:
2346 return true;
2347 }
2348 return false;
2349}
2350
2351static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2352{
2353 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Ben Chenge9695e52009-06-16 16:11:47 -07002354 int reg0, reg1, reg2;
2355
Ben Chengba4fc8b2009-06-01 13:00:29 -07002356 /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
2357 if (dalvikOpCode == OP_CONST_WIDE_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002358 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002359 int BBBB = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002360
2361 reg0 = selectFirstRegister(cUnit, vNone, true);
2362 reg1 = NEXT_REG(reg0);
2363 reg2 = NEXT_REG(reg1);
2364
2365 loadConstant(cUnit, reg0, BBBB);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002366 opRegRegImm(cUnit, OP_ASR, reg1, reg0, 31, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002367
2368 /* Save the long values to the specified Dalvik register pair */
Ben Chenge9695e52009-06-16 16:11:47 -07002369 storeValuePair(cUnit, reg0, reg1, vDest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002370 } else if (dalvikOpCode == OP_CONST_16) {
Ben Chenge9695e52009-06-16 16:11:47 -07002371 int vDest = mir->dalvikInsn.vA;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002372 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002373
Ben Chenge9695e52009-06-16 16:11:47 -07002374 reg0 = selectFirstRegister(cUnit, vNone, false);
2375 reg1 = NEXT_REG(reg0);
2376
2377 loadConstant(cUnit, reg0, BBBB);
2378 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002379 } else {
2380 return true;
2381 }
2382 return false;
2383}
2384
2385/* Compare agaist zero */
2386static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002387 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002388{
2389 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002390 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002391 int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002392
Ben Chenge9695e52009-06-16 16:11:47 -07002393 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002394 opRegImm(cUnit, OP_CMP, reg0, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002395
Bill Buzbee270c1d62009-08-13 16:58:07 -07002396//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002397 switch (dalvikOpCode) {
2398 case OP_IF_EQZ:
2399 cond = ARM_COND_EQ;
2400 break;
2401 case OP_IF_NEZ:
2402 cond = ARM_COND_NE;
2403 break;
2404 case OP_IF_LTZ:
2405 cond = ARM_COND_LT;
2406 break;
2407 case OP_IF_GEZ:
2408 cond = ARM_COND_GE;
2409 break;
2410 case OP_IF_GTZ:
2411 cond = ARM_COND_GT;
2412 break;
2413 case OP_IF_LEZ:
2414 cond = ARM_COND_LE;
2415 break;
2416 default:
2417 cond = 0;
2418 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2419 dvmAbort();
2420 }
2421 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2422 /* This mostly likely will be optimized away in a later phase */
2423 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2424 return false;
2425}
2426
2427static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2428{
2429 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2430 int vSrc = mir->dalvikInsn.vB;
2431 int vDest = mir->dalvikInsn.vA;
2432 int lit = mir->dalvikInsn.vC;
Bill Buzbee270c1d62009-08-13 16:58:07 -07002433 OpKind op;
Ben Chenge9695e52009-06-16 16:11:47 -07002434 int reg0, reg1, regDest;
2435
2436 reg0 = selectFirstRegister(cUnit, vSrc, false);
2437 reg1 = NEXT_REG(reg0);
2438 regDest = NEXT_REG(reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002439
Ben Chengba4fc8b2009-06-01 13:00:29 -07002440 int __aeabi_idivmod(int op1, int op2);
2441 int __aeabi_idiv(int op1, int op2);
2442
2443 switch (dalvikOpCode) {
2444 case OP_ADD_INT_LIT8:
2445 case OP_ADD_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002446 loadValue(cUnit, vSrc, reg0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002447 opRegImm(cUnit, OP_ADD, reg0, lit, reg1);
2448 storeValue(cUnit, reg0, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002449 break;
2450
2451 case OP_RSUB_INT_LIT8:
2452 case OP_RSUB_INT:
Ben Chenge9695e52009-06-16 16:11:47 -07002453 loadValue(cUnit, vSrc, reg1);
2454 loadConstant(cUnit, reg0, lit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002455 opRegRegReg(cUnit, OP_SUB, regDest, reg0, reg1);
2456 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002457 break;
2458
2459 case OP_MUL_INT_LIT8:
2460 case OP_MUL_INT_LIT16:
2461 case OP_AND_INT_LIT8:
2462 case OP_AND_INT_LIT16:
2463 case OP_OR_INT_LIT8:
2464 case OP_OR_INT_LIT16:
2465 case OP_XOR_INT_LIT8:
2466 case OP_XOR_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002467 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002468 switch (dalvikOpCode) {
2469 case OP_MUL_INT_LIT8:
2470 case OP_MUL_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002471 op = OP_MUL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002472 break;
2473 case OP_AND_INT_LIT8:
2474 case OP_AND_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002475 op = OP_AND;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002476 break;
2477 case OP_OR_INT_LIT8:
2478 case OP_OR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002479 op = OP_OR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002480 break;
2481 case OP_XOR_INT_LIT8:
2482 case OP_XOR_INT_LIT16:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002483 op = OP_XOR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002484 break;
2485 default:
2486 dvmAbort();
2487 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002488 opRegRegImm(cUnit, op, regDest, reg0, lit, reg1);
2489 storeValue(cUnit, regDest, vDest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002490 break;
2491
2492 case OP_SHL_INT_LIT8:
2493 case OP_SHR_INT_LIT8:
2494 case OP_USHR_INT_LIT8:
Ben Chenge9695e52009-06-16 16:11:47 -07002495 loadValue(cUnit, vSrc, reg0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002496 switch (dalvikOpCode) {
2497 case OP_SHL_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002498 op = OP_LSL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002499 break;
2500 case OP_SHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002501 op = OP_ASR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002502 break;
2503 case OP_USHR_INT_LIT8:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002504 op = OP_LSR;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002505 break;
2506 default: 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_DIV_INT_LIT8:
2513 case OP_DIV_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002514 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002515 if (lit == 0) {
2516 /* Let the interpreter deal with div by 0 */
2517 genInterpSingleStep(cUnit, mir);
2518 return false;
2519 }
2520 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2521 loadConstant(cUnit, r1, lit);
2522 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002523 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002524 storeValue(cUnit, r0, vDest, r2);
2525 break;
2526
2527 case OP_REM_INT_LIT8:
2528 case OP_REM_INT_LIT16:
Ben Chenge9695e52009-06-16 16:11:47 -07002529 /* Register usage based on the calling convention */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002530 if (lit == 0) {
2531 /* Let the interpreter deal with div by 0 */
2532 genInterpSingleStep(cUnit, mir);
2533 return false;
2534 }
2535 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2536 loadConstant(cUnit, r1, lit);
2537 loadValue(cUnit, vSrc, r0);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002538 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002539 storeValue(cUnit, r1, vDest, r2);
2540 break;
2541 default:
2542 return true;
2543 }
2544 return false;
2545}
2546
2547static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2548{
2549 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2550 int fieldOffset;
2551
2552 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2553 InstField *pInstField = (InstField *)
2554 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
2555 int fieldOffset;
2556
2557 assert(pInstField != NULL);
2558 fieldOffset = pInstField->byteOffset;
2559 } else {
2560 /* To make the compiler happy */
2561 fieldOffset = 0;
2562 }
2563 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002564 case OP_NEW_ARRAY: {
2565 void *classPtr = (void*)
2566 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2567 assert(classPtr != NULL);
2568 loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
2569 loadConstant(cUnit, r0, (int) classPtr );
2570 loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002571 ArmLIR *pcrLabel =
Ben Chengba4fc8b2009-06-01 13:00:29 -07002572 genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
2573 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002574 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
2575 opReg(cUnit, OP_BLX, r4PC);
2576 /* Note: on failure, we'll bail and reinterpret */
Ben Chenge9695e52009-06-16 16:11:47 -07002577 genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002578 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2579 break;
2580 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002581 case OP_INSTANCE_OF: {
2582 ClassObject *classPtr =
2583 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2584 assert(classPtr != NULL);
Ben Cheng752c7942009-06-22 10:50:07 -07002585 loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002586 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002587//TUNING: compare to 0 primative to allow use of CB[N]Z
2588 opRegImm(cUnit, OP_CMP, r0, 0, rNone); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07002589 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002590 ArmLIR *branch1 = opImmImm(cUnit, OP_COND_BR, 4, ARM_COND_EQ);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002591 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002592 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002593 loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07002594 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002595 opRegReg(cUnit, OP_CMP, r1, r2);
2596 ArmLIR *branch2 = opImmImm(cUnit, OP_COND_BR, 2, ARM_COND_EQ);
2597 opRegReg(cUnit, OP_MOV, r0, r1);
2598 opRegReg(cUnit, OP_MOV, r1, r2);
2599 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002600 /* branch target here */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002601 ArmLIR *target = newLIR0(cUnit, ARM_PSEUDO_TARGET_LABEL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002602 storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
2603 branch1->generic.target = (LIR *)target;
2604 branch2->generic.target = (LIR *)target;
2605 break;
2606 }
2607 case OP_IGET_WIDE:
2608 genIGetWide(cUnit, mir, fieldOffset);
2609 break;
2610 case OP_IGET:
2611 case OP_IGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002612 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002613 break;
2614 case OP_IGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002615 genIGet(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002616 break;
2617 case OP_IGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002618 genIGet(cUnit, mir, SIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002619 break;
2620 case OP_IGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002621 genIGet(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002622 break;
2623 case OP_IGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002624 genIGet(cUnit, mir, SIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002625 break;
2626 case OP_IPUT_WIDE:
2627 genIPutWide(cUnit, mir, fieldOffset);
2628 break;
2629 case OP_IPUT:
2630 case OP_IPUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002631 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002632 break;
2633 case OP_IPUT_SHORT:
2634 case OP_IPUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002635 genIPut(cUnit, mir, UNSIGNED_HALF, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002636 break;
2637 case OP_IPUT_BYTE:
2638 case OP_IPUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002639 genIPut(cUnit, mir, UNSIGNED_BYTE, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002640 break;
2641 default:
2642 return true;
2643 }
2644 return false;
2645}
2646
2647static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
2648{
2649 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2650 int fieldOffset = mir->dalvikInsn.vC;
2651 switch (dalvikOpCode) {
2652 case OP_IGET_QUICK:
2653 case OP_IGET_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002654 genIGet(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002655 break;
2656 case OP_IPUT_QUICK:
2657 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002658 genIPut(cUnit, mir, WORD, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002659 break;
2660 case OP_IGET_WIDE_QUICK:
2661 genIGetWide(cUnit, mir, fieldOffset);
2662 break;
2663 case OP_IPUT_WIDE_QUICK:
2664 genIPutWide(cUnit, mir, fieldOffset);
2665 break;
2666 default:
2667 return true;
2668 }
2669 return false;
2670
2671}
2672
2673/* Compare agaist zero */
2674static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002675 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002676{
2677 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002678 ArmConditionCode cond;
Ben Chenge9695e52009-06-16 16:11:47 -07002679 int reg0, reg1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002680
Ben Chenge9695e52009-06-16 16:11:47 -07002681 if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
2682 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
2683 reg1 = NEXT_REG(reg0);
2684 /* Load vB first since vA can be fetched via a move */
2685 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2686 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2687 } else {
2688 reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
2689 reg1 = NEXT_REG(reg0);
2690 /* Load vA first since vB can be fetched via a move */
2691 loadValue(cUnit, mir->dalvikInsn.vA, reg0);
2692 loadValue(cUnit, mir->dalvikInsn.vB, reg1);
2693 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002694 opRegReg(cUnit, OP_CMP, reg0, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002695
2696 switch (dalvikOpCode) {
2697 case OP_IF_EQ:
2698 cond = ARM_COND_EQ;
2699 break;
2700 case OP_IF_NE:
2701 cond = ARM_COND_NE;
2702 break;
2703 case OP_IF_LT:
2704 cond = ARM_COND_LT;
2705 break;
2706 case OP_IF_GE:
2707 cond = ARM_COND_GE;
2708 break;
2709 case OP_IF_GT:
2710 cond = ARM_COND_GT;
2711 break;
2712 case OP_IF_LE:
2713 cond = ARM_COND_LE;
2714 break;
2715 default:
2716 cond = 0;
2717 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
2718 dvmAbort();
2719 }
2720 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2721 /* This mostly likely will be optimized away in a later phase */
2722 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2723 return false;
2724}
2725
2726static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
2727{
2728 OpCode opCode = mir->dalvikInsn.opCode;
2729 int vSrc1Dest = mir->dalvikInsn.vA;
2730 int vSrc2 = mir->dalvikInsn.vB;
Ben Chenge9695e52009-06-16 16:11:47 -07002731 int reg0, reg1, reg2;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002732
2733 switch (opCode) {
2734 case OP_MOVE_16:
2735 case OP_MOVE_OBJECT_16:
2736 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07002737 case OP_MOVE_OBJECT_FROM16: {
2738 reg0 = selectFirstRegister(cUnit, vSrc2, false);
2739 reg1 = NEXT_REG(reg0);
2740 loadValue(cUnit, vSrc2, reg0);
2741 storeValue(cUnit, reg0, vSrc1Dest, reg1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002742 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002743 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002744 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07002745 case OP_MOVE_WIDE_FROM16: {
2746 reg0 = selectFirstRegister(cUnit, vSrc2, true);
2747 reg1 = NEXT_REG(reg0);
2748 reg2 = NEXT_REG(reg1);
2749 loadValuePair(cUnit, vSrc2, reg0, reg1);
2750 storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002751 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002752 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002753 default:
2754 return true;
2755 }
2756 return false;
2757}
2758
2759static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
2760{
2761 OpCode opCode = mir->dalvikInsn.opCode;
2762 int vA = mir->dalvikInsn.vA;
2763 int vB = mir->dalvikInsn.vB;
2764 int vC = mir->dalvikInsn.vC;
2765
Ben Chenge9695e52009-06-16 16:11:47 -07002766 /* Don't optimize for register usage since out-of-line handlers are used */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002767 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
2768 return genArithOp( cUnit, mir );
2769 }
2770
2771 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07002772 case OP_CMPL_FLOAT:
2773 case OP_CMPG_FLOAT:
2774 case OP_CMPL_DOUBLE:
2775 case OP_CMPG_DOUBLE:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002776 return genCmpX(cUnit, mir, vA, vB, vC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002777 case OP_CMP_LONG:
2778 loadValuePair(cUnit,vB, r0, r1);
2779 loadValuePair(cUnit, vC, r2, r3);
2780 genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
2781 storeValue(cUnit, r0, vA, r1);
2782 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002783 case OP_AGET_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002784 genArrayGet(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002785 break;
2786 case OP_AGET:
2787 case OP_AGET_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002788 genArrayGet(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002789 break;
2790 case OP_AGET_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002791 genArrayGet(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002792 break;
2793 case OP_AGET_BYTE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002794 genArrayGet(cUnit, mir, SIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002795 break;
2796 case OP_AGET_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002797 genArrayGet(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002798 break;
2799 case OP_AGET_SHORT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002800 genArrayGet(cUnit, mir, SIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002801 break;
2802 case OP_APUT_WIDE:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002803 genArrayPut(cUnit, mir, LONG, vB, vC, vA, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002804 break;
2805 case OP_APUT:
2806 case OP_APUT_OBJECT:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002807 genArrayPut(cUnit, mir, WORD, vB, vC, vA, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002808 break;
2809 case OP_APUT_SHORT:
2810 case OP_APUT_CHAR:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002811 genArrayPut(cUnit, mir, UNSIGNED_HALF, vB, vC, vA, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002812 break;
2813 case OP_APUT_BYTE:
2814 case OP_APUT_BOOLEAN:
Bill Buzbee270c1d62009-08-13 16:58:07 -07002815 genArrayPut(cUnit, mir, UNSIGNED_BYTE, vB, vC, vA, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002816 break;
2817 default:
2818 return true;
2819 }
2820 return false;
2821}
2822
2823static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
2824{
2825 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2826 switch (dalvikOpCode) {
2827 case OP_FILL_ARRAY_DATA: {
2828 loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
2829 loadValue(cUnit, mir->dalvikInsn.vA, r0);
2830 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
2831 (int) (cUnit->method->insns + mir->offset));
2832 genExportPC(cUnit, mir, r2, r3 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002833 opReg(cUnit, OP_BLX, r4PC);
Ben Chenge9695e52009-06-16 16:11:47 -07002834 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002835 break;
2836 }
2837 /*
2838 * TODO
2839 * - Add a 1 to 3-entry per-location cache here to completely
2840 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
2841 * - Use out-of-line handlers for both of these
2842 */
2843 case OP_PACKED_SWITCH:
2844 case OP_SPARSE_SWITCH: {
2845 if (dalvikOpCode == OP_PACKED_SWITCH) {
2846 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
2847 } else {
2848 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
2849 }
2850 loadValue(cUnit, mir->dalvikInsn.vA, r1);
2851 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
2852 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002853 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002854 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002855 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2856 jitToInterpEntries.dvmJitToInterpNoChain), r2);
2857 opRegReg(cUnit, OP_ADD, r0, r0);
2858 opRegRegReg(cUnit, OP_ADD, r4PC, r0, r1);
2859 opReg(cUnit, OP_BLX, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002860 break;
2861 }
2862 default:
2863 return true;
2864 }
2865 return false;
2866}
2867
2868static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002869 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002870{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07002871 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002872 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002873
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07002874 if (bb->fallThrough != NULL)
2875 retChainingCell = &labelList[bb->fallThrough->id];
2876
Ben Chengba4fc8b2009-06-01 13:00:29 -07002877 DecodedInstruction *dInsn = &mir->dalvikInsn;
2878 switch (mir->dalvikInsn.opCode) {
2879 /*
2880 * calleeMethod = this->clazz->vtable[
2881 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
2882 * ]
2883 */
2884 case OP_INVOKE_VIRTUAL:
2885 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002886 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002887 int methodIndex =
2888 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
2889 methodIndex;
2890
2891 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
2892 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2893 else
2894 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2895
Ben Cheng38329f52009-07-07 14:19:20 -07002896 genInvokeVirtualCommon(cUnit, mir, methodIndex,
2897 retChainingCell,
2898 predChainingCell,
2899 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002900 break;
2901 }
2902 /*
2903 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
2904 * ->pResMethods[BBBB]->methodIndex]
2905 */
2906 /* TODO - not excersized in RunPerf.jar */
2907 case OP_INVOKE_SUPER:
2908 case OP_INVOKE_SUPER_RANGE: {
2909 int mIndex = cUnit->method->clazz->pDvmDex->
2910 pResMethods[dInsn->vB]->methodIndex;
2911 const Method *calleeMethod =
2912 cUnit->method->clazz->super->vtable[mIndex];
2913
2914 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
2915 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2916 else
2917 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2918
2919 /* r0 = calleeMethod */
2920 loadConstant(cUnit, r0, (int) calleeMethod);
2921
Ben Cheng38329f52009-07-07 14:19:20 -07002922 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2923 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002924 break;
2925 }
2926 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2927 case OP_INVOKE_DIRECT:
2928 case OP_INVOKE_DIRECT_RANGE: {
2929 const Method *calleeMethod =
2930 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2931
2932 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
2933 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
2934 else
2935 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
2936
2937 /* r0 = calleeMethod */
2938 loadConstant(cUnit, r0, (int) calleeMethod);
2939
Ben Cheng38329f52009-07-07 14:19:20 -07002940 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2941 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002942 break;
2943 }
2944 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
2945 case OP_INVOKE_STATIC:
2946 case OP_INVOKE_STATIC_RANGE: {
2947 const Method *calleeMethod =
2948 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
2949
2950 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
2951 genProcessArgsNoRange(cUnit, mir, dInsn,
2952 NULL /* no null check */);
2953 else
2954 genProcessArgsRange(cUnit, mir, dInsn,
2955 NULL /* no null check */);
2956
2957 /* r0 = calleeMethod */
2958 loadConstant(cUnit, r0, (int) calleeMethod);
2959
Ben Cheng38329f52009-07-07 14:19:20 -07002960 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
2961 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002962 break;
2963 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07002964/*
2965 * TODO: When we move to using upper registers in Thumb2, make sure
2966 * the register allocater is told that r9, r10, & r12 are killed
2967 * here.
2968 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002969 /*
2970 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
2971 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07002972 *
2973 * Given "invoke-interface {v0}", the following is the generated code:
2974 *
2975 * 0x426a9abe : ldr r0, [r5, #0] --+
2976 * 0x426a9ac0 : mov r7, r5 |
2977 * 0x426a9ac2 : sub r7, #24 |
2978 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
2979 * 0x426a9ac6 : beq 0x426a9afe |
2980 * 0x426a9ac8 : stmia r7, <r0> --+
2981 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
2982 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
2983 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
2984 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
2985 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
2986 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
2987 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
2988 * 0x426a9ad8 : mov r9, r1 --+
2989 * 0x426a9ada : mov r10, r2 |
2990 * 0x426a9adc : mov r12, r3 |
2991 * 0x426a9ade : mov r0, r3 |
2992 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
2993 * 0x426a9ae2 : ldr r2, [pc, #76] |
2994 * 0x426a9ae4 : ldr r3, [pc, #68] |
2995 * 0x426a9ae6 : ldr r7, [pc, #64] |
2996 * 0x426a9ae8 : blx r7 --+
2997 * 0x426a9aea : mov r1, r9 --> r1 <- rechain count
2998 * 0x426a9aec : cmp r1, #0 --> compare against 0
2999 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3000 * 0x426a9af0 : ldr r7, [r6, #96] --+
3001 * 0x426a9af2 : mov r2, r10 | dvmJitToPatchPredictedChain
3002 * 0x426a9af4 : mov r3, r12 |
3003 * 0x426a9af6 : blx r7 --+
3004 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3005 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3006 * 0x426a9afc : blx_2 see above --+
3007 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3008 * 0x426a9afe (0042): ldr r0, [pc, #52]
3009 * Exception_Handling:
3010 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3011 * 0x426a9b02 (0046): blx r1
3012 * 0x426a9b04 (0048): .align4
3013 * -------- chaining cell (hot): 0x0021
3014 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3015 * 0x426a9b06 (004a): blx r0
3016 * 0x426a9b08 (004c): data 0x7872(30834)
3017 * 0x426a9b0a (004e): data 0x428b(17035)
3018 * 0x426a9b0c (0050): .align4
3019 * -------- chaining cell (predicted)
3020 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3021 * 0x426a9b0e (0052): data 0x0000(0)
3022 * 0x426a9b10 (0054): data 0x0000(0) --> class
3023 * 0x426a9b12 (0056): data 0x0000(0)
3024 * 0x426a9b14 (0058): data 0x0000(0) --> method
3025 * 0x426a9b16 (005a): data 0x0000(0)
3026 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3027 * 0x426a9b1a (005e): data 0x0000(0)
3028 * 0x426a9b28 (006c): .word (0xad0392a5)
3029 * 0x426a9b2c (0070): .word (0x6e750)
3030 * 0x426a9b30 (0074): .word (0x4109a618)
3031 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003032 */
3033 case OP_INVOKE_INTERFACE:
3034 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003035 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003036 int methodIndex = dInsn->vB;
3037
3038 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3039 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3040 else
3041 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3042
Ben Cheng38329f52009-07-07 14:19:20 -07003043 /* "this" is already left in r0 by genProcessArgs* */
3044
3045 /* r4PC = dalvikCallsite */
3046 loadConstant(cUnit, r4PC,
3047 (int) (cUnit->method->insns + mir->offset));
3048
3049 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003050 ArmLIR *addrRetChain =
3051 opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003052 addrRetChain->generic.target = (LIR *) retChainingCell;
3053
3054 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003055 ArmLIR *predictedChainingCell =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003056 opRegRegImm(cUnit, OP_ADD, r2, rpc, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003057 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3058
3059 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3060
3061 /* return through lr - jump to the chaining cell */
3062 genUnconditionalBranch(cUnit, predChainingCell);
3063
3064 /*
3065 * null-check on "this" may have been eliminated, but we still need
3066 * a PC-reconstruction label for stack overflow bailout.
3067 */
3068 if (pcrLabel == NULL) {
3069 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003070 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
3071 pcrLabel->opCode = ARM_PSEUDO_PC_RECONSTRUCTION_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003072 pcrLabel->operands[0] = dPC;
3073 pcrLabel->operands[1] = mir->offset;
3074 /* Insert the place holder to the growable list */
3075 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3076 }
3077
3078 /* return through lr+2 - punt to the interpreter */
3079 genUnconditionalBranch(cUnit, pcrLabel);
3080
3081 /*
3082 * return through lr+4 - fully resolve the callee method.
3083 * r1 <- count
3084 * r2 <- &predictedChainCell
3085 * r3 <- this->class
3086 * r4 <- dPC
3087 * r7 <- this->class->vtable
3088 */
3089
3090 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003091 opRegReg(cUnit, OP_MOV, r9, r1);
3092 opRegReg(cUnit, OP_MOV, r10, r2);
3093 opRegReg(cUnit, OP_MOV, r12, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003094
Ben Chengba4fc8b2009-06-01 13:00:29 -07003095 /* r0 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003096 opRegReg(cUnit, OP_MOV, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003097
3098 /* r1 = BBBB */
3099 loadConstant(cUnit, r1, dInsn->vB);
3100
3101 /* r2 = method (caller) */
3102 loadConstant(cUnit, r2, (int) cUnit->method);
3103
3104 /* r3 = pDvmDex */
3105 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3106
3107 loadConstant(cUnit, r7,
3108 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003109 opReg(cUnit, OP_BLX, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003110
3111 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3112
Bill Buzbee270c1d62009-08-13 16:58:07 -07003113 opRegReg(cUnit, OP_MOV, r1, r9);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003114
Ben Cheng38329f52009-07-07 14:19:20 -07003115 /* Check if rechain limit is reached */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003116 opRegImm(cUnit, OP_CMP, r1, 0, rNone);
Ben Cheng38329f52009-07-07 14:19:20 -07003117
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003118 ArmLIR *bypassRechaining =
Bill Buzbee270c1d62009-08-13 16:58:07 -07003119 opImmImm(cUnit, OP_COND_BR, 0, ARM_COND_GT);
Ben Cheng38329f52009-07-07 14:19:20 -07003120
Bill Buzbee270c1d62009-08-13 16:58:07 -07003121 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3122 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003123
Bill Buzbee270c1d62009-08-13 16:58:07 -07003124 opRegReg(cUnit, OP_MOV, r2, r10);
3125 opRegReg(cUnit, OP_MOV, r3, r12);
Ben Cheng38329f52009-07-07 14:19:20 -07003126
3127 /*
3128 * r0 = calleeMethod
3129 * r2 = &predictedChainingCell
3130 * r3 = class
3131 *
3132 * &returnChainingCell has been loaded into r1 but is not needed
3133 * when patching the chaining cell and will be clobbered upon
3134 * returning so it will be reconstructed again.
3135 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003136 opReg(cUnit, OP_BLX, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003137
3138 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003139 addrRetChain = opRegRegImm(cUnit, OP_ADD, r1, rpc, 0, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003140 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003141
3142 bypassRechaining->generic.target = (LIR *) addrRetChain;
3143
Ben Chengba4fc8b2009-06-01 13:00:29 -07003144 /*
3145 * r0 = this, r1 = calleeMethod,
3146 * r1 = &ChainingCell,
3147 * r4PC = callsiteDPC,
3148 */
3149 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3150#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003151 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003152#endif
3153 /* Handle exceptions using the interpreter */
3154 genTrap(cUnit, mir->offset, pcrLabel);
3155 break;
3156 }
3157 /* NOP */
3158 case OP_INVOKE_DIRECT_EMPTY: {
3159 return false;
3160 }
3161 case OP_FILLED_NEW_ARRAY:
3162 case OP_FILLED_NEW_ARRAY_RANGE: {
3163 /* Just let the interpreter deal with these */
3164 genInterpSingleStep(cUnit, mir);
3165 break;
3166 }
3167 default:
3168 return true;
3169 }
3170 return false;
3171}
3172
3173static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003174 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003175{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003176 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3177 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3178 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003179
3180 DecodedInstruction *dInsn = &mir->dalvikInsn;
3181 switch (mir->dalvikInsn.opCode) {
3182 /* calleeMethod = this->clazz->vtable[BBBB] */
3183 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3184 case OP_INVOKE_VIRTUAL_QUICK: {
3185 int methodIndex = dInsn->vB;
3186 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3187 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3188 else
3189 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3190
Ben Cheng38329f52009-07-07 14:19:20 -07003191 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3192 retChainingCell,
3193 predChainingCell,
3194 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003195 break;
3196 }
3197 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3198 case OP_INVOKE_SUPER_QUICK:
3199 case OP_INVOKE_SUPER_QUICK_RANGE: {
3200 const Method *calleeMethod =
3201 cUnit->method->clazz->super->vtable[dInsn->vB];
3202
3203 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3204 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3205 else
3206 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3207
3208 /* r0 = calleeMethod */
3209 loadConstant(cUnit, r0, (int) calleeMethod);
3210
Ben Cheng38329f52009-07-07 14:19:20 -07003211 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3212 calleeMethod);
3213 /* Handle exceptions using the interpreter */
3214 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003215 break;
3216 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003217 default:
3218 return true;
3219 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003220 return false;
3221}
3222
3223/*
3224 * NOTE: We assume here that the special native inline routines
3225 * are side-effect free. By making this assumption, we can safely
3226 * re-execute the routine from the interpreter if it decides it
3227 * wants to throw an exception. We still need to EXPORT_PC(), though.
3228 */
3229static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3230{
3231 DecodedInstruction *dInsn = &mir->dalvikInsn;
3232 switch( mir->dalvikInsn.opCode) {
3233 case OP_EXECUTE_INLINE: {
3234 unsigned int i;
3235 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003236 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003237 int operation = dInsn->vB;
3238
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003239 switch (operation) {
3240 case INLINE_EMPTYINLINEMETHOD:
3241 return false; /* Nop */
3242 case INLINE_STRING_LENGTH:
3243 return genInlinedStringLength(cUnit, mir);
3244 case INLINE_MATH_ABS_INT:
3245 return genInlinedAbsInt(cUnit, mir);
3246 case INLINE_MATH_ABS_LONG:
3247 return genInlinedAbsLong(cUnit, mir);
3248 case INLINE_MATH_MIN_INT:
3249 return genInlinedMinMaxInt(cUnit, mir, true);
3250 case INLINE_MATH_MAX_INT:
3251 return genInlinedMinMaxInt(cUnit, mir, false);
3252 case INLINE_STRING_CHARAT:
3253 return genInlinedStringCharAt(cUnit, mir);
3254 case INLINE_MATH_SQRT:
3255 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003256 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003257 else
3258 break; /* Handle with C routine */
3259 case INLINE_MATH_COS:
3260 if (genInlineCos(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003261 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003262 else
3263 break; /* Handle with C routine */
3264 case INLINE_MATH_SIN:
3265 if (genInlineSin(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003266 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003267 else
3268 break; /* Handle with C routine */
3269 case INLINE_MATH_ABS_FLOAT:
3270 return genInlinedAbsFloat(cUnit, mir);
3271 case INLINE_MATH_ABS_DOUBLE:
3272 return genInlinedAbsDouble(cUnit, mir);
3273 case INLINE_STRING_COMPARETO:
3274 case INLINE_STRING_EQUALS:
3275 break;
3276 default:
3277 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003278 }
3279
3280 /* Materialize pointer to retval & push */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003281 opRegReg(cUnit, OP_MOV, r4PC, rGLUE);
3282 opRegImm(cUnit, OP_ADD, r4PC, offset, rNone);
3283
Ben Chengba4fc8b2009-06-01 13:00:29 -07003284 /* Push r4 and (just to take up space) r5) */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003285 opImm(cUnit, OP_PUSH, (1 << r4PC | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003286
3287 /* Get code pointer to inline routine */
3288 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
3289
3290 /* Export PC */
3291 genExportPC(cUnit, mir, r0, r1 );
3292
3293 /* Load arguments to r0 through r3 as applicable */
3294 for (i=0; i < dInsn->vA; i++) {
3295 loadValue(cUnit, dInsn->arg[i], i);
3296 }
3297 /* Call inline routine */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003298 opReg(cUnit, OP_BLX, r4PC);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003299
3300 /* Strip frame */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003301 opRegImm(cUnit, OP_ADD, r13, 8, rNone);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003302
3303 /* Did we throw? If so, redo under interpreter*/
Ben Chenge9695e52009-06-16 16:11:47 -07003304 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003305
Ben Chenge9695e52009-06-16 16:11:47 -07003306 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003307 break;
3308 }
3309 default:
3310 return true;
3311 }
3312 return false;
3313}
3314
3315static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3316{
3317 loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3318 loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3319 storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
3320 return false;
3321}
3322
Ben Chengba4fc8b2009-06-01 13:00:29 -07003323/*
3324 * The following are special processing routines that handle transfer of
3325 * controls between compiled code and the interpreter. Certain VM states like
3326 * Dalvik PC and special-purpose registers are reconstructed here.
3327 */
3328
Ben Cheng1efc9c52009-06-08 18:25:27 -07003329/* Chaining cell for code that may need warmup. */
3330static void handleNormalChainingCell(CompilationUnit *cUnit,
3331 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003332{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003333 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3334 jitToInterpEntries.dvmJitToInterpNormal), r0);
3335 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003336 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3337}
3338
3339/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003340 * Chaining cell for instructions that immediately following already translated
3341 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003342 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003343static void handleHotChainingCell(CompilationUnit *cUnit,
3344 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003345{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003346 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3347 jitToInterpEntries.dvmJitToTraceSelect), r0);
3348 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003349 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3350}
3351
Jeff Hao97319a82009-08-12 16:57:15 -07003352#if defined(WITH_SELF_VERIFICATION)
3353/* Chaining cell for branches that branch back into the same basic block */
3354static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3355 unsigned int offset)
3356{
3357 newLIR3(cUnit, THUMB_LDR_RRI5, r0, rGLUE,
3358 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
3359 newLIR1(cUnit, THUMB_BLX_R, r0);
3360 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3361}
3362
3363#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003364/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003365static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3366 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003367{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003368 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3369 jitToInterpEntries.dvmJitToTraceSelect), r0);
3370 opReg(cUnit, OP_BLX, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003371 addWordData(cUnit, (int) (callee->insns), true);
3372}
3373
Ben Cheng38329f52009-07-07 14:19:20 -07003374/* Chaining cell for monomorphic method invocations. */
3375static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3376{
3377
3378 /* Should not be executed in the initial state */
3379 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3380 /* To be filled: class */
3381 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3382 /* To be filled: method */
3383 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3384 /*
3385 * Rechain count. The initial value of 0 here will trigger chaining upon
3386 * the first invocation of this callsite.
3387 */
3388 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3389}
3390
Ben Chengba4fc8b2009-06-01 13:00:29 -07003391/* Load the Dalvik PC into r0 and jump to the specified target */
3392static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003393 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003394{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003395 ArmLIR **pcrLabel =
3396 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003397 int numElems = cUnit->pcReconstructionList.numUsed;
3398 int i;
3399 for (i = 0; i < numElems; i++) {
3400 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3401 /* r0 = dalvik PC */
3402 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3403 genUnconditionalBranch(cUnit, targetLabel);
3404 }
3405}
3406
3407/* Entry function to invoke the backend of the JIT compiler */
3408void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
3409{
3410 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003411 ArmLIR *labelList =
3412 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003413 GrowableList chainingListByType[CHAINING_CELL_LAST];
3414 int i;
3415
3416 /*
Ben Cheng38329f52009-07-07 14:19:20 -07003417 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003418 */
3419 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3420 dvmInitGrowableList(&chainingListByType[i], 2);
3421 }
3422
3423 BasicBlock **blockList = cUnit->blockList;
3424
Bill Buzbee6e963e12009-06-17 16:56:19 -07003425 if (cUnit->executionCount) {
3426 /*
3427 * Reserve 6 bytes at the beginning of the trace
3428 * +----------------------------+
3429 * | execution count (4 bytes) |
3430 * +----------------------------+
3431 * | chain cell offset (2 bytes)|
3432 * +----------------------------+
3433 * ...and then code to increment the execution
3434 * count:
3435 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
3436 * sub r0, #10 @ back up to addr of executionCount
3437 * ldr r1, [r0]
3438 * add r1, #1
3439 * str r1, [r0]
3440 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003441 newLIR1(cUnit, ARM_16BIT_DATA, 0);
3442 newLIR1(cUnit, ARM_16BIT_DATA, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07003443 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003444 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003445 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07003446 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003447 newLIR2(cUnit, THUMB_MOV_RR_H2L, r0, rpc & THUMB_REG_MASK);
3448 newLIR2(cUnit, THUMB_SUB_RI8, r0, 10);
3449 newLIR3(cUnit, THUMB_LDR_RRI5, r1, r0, 0);
3450 newLIR2(cUnit, THUMB_ADD_RI8, r1, 1);
3451 newLIR3(cUnit, THUMB_STR_RRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003452 } else {
3453 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07003454 cUnit->chainCellOffsetLIR =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003455 (LIR *) newLIR1(cUnit, ARM_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07003456 cUnit->headerSize = 2;
3457 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07003458
Ben Chengba4fc8b2009-06-01 13:00:29 -07003459 /* Handle the content in each basic block */
3460 for (i = 0; i < cUnit->numBlocks; i++) {
3461 blockList[i]->visited = true;
3462 MIR *mir;
3463
3464 labelList[i].operands[0] = blockList[i]->startOffset;
3465
3466 if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
3467 /*
3468 * Append the label pseudo LIR first. Chaining cells will be handled
3469 * separately afterwards.
3470 */
3471 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
3472 }
3473
3474 if (blockList[i]->blockType == DALVIK_BYTECODE) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003475 labelList[i].opCode = ARM_PSEUDO_NORMAL_BLOCK_LABEL;
Ben Chenge9695e52009-06-16 16:11:47 -07003476 /* Reset the register state */
3477 resetRegisterScoreboard(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003478 } else {
3479 switch (blockList[i]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003480 case CHAINING_CELL_NORMAL:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003481 labelList[i].opCode = ARM_PSEUDO_CHAINING_CELL_NORMAL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003482 /* handle the codegen later */
3483 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003484 &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003485 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003486 case CHAINING_CELL_INVOKE_SINGLETON:
3487 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003488 ARM_PSEUDO_CHAINING_CELL_INVOKE_SINGLETON;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003489 labelList[i].operands[0] =
3490 (int) blockList[i]->containingMethod;
3491 /* handle the codegen later */
3492 dvmInsertGrowableList(
Ben Cheng38329f52009-07-07 14:19:20 -07003493 &chainingListByType[CHAINING_CELL_INVOKE_SINGLETON],
3494 (void *) i);
3495 break;
3496 case CHAINING_CELL_INVOKE_PREDICTED:
3497 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003498 ARM_PSEUDO_CHAINING_CELL_INVOKE_PREDICTED;
Ben Cheng38329f52009-07-07 14:19:20 -07003499 /* handle the codegen later */
3500 dvmInsertGrowableList(
3501 &chainingListByType[CHAINING_CELL_INVOKE_PREDICTED],
3502 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003503 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003504 case CHAINING_CELL_HOT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07003505 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003506 ARM_PSEUDO_CHAINING_CELL_HOT;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003507 /* handle the codegen later */
3508 dvmInsertGrowableList(
Ben Cheng1efc9c52009-06-08 18:25:27 -07003509 &chainingListByType[CHAINING_CELL_HOT],
Ben Chengba4fc8b2009-06-01 13:00:29 -07003510 (void *) i);
3511 break;
3512 case PC_RECONSTRUCTION:
3513 /* Make sure exception handling block is next */
3514 labelList[i].opCode =
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003515 ARM_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003516 assert (i == cUnit->numBlocks - 2);
3517 handlePCReconstruction(cUnit, &labelList[i+1]);
3518 break;
3519 case EXCEPTION_HANDLING:
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003520 labelList[i].opCode = ARM_PSEUDO_EH_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003521 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07003522 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3523 jitToInterpEntries.dvmJitToInterpPunt),
3524 r1);
3525 opReg(cUnit, OP_BLX, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003526 }
3527 break;
Jeff Hao97319a82009-08-12 16:57:15 -07003528#if defined(WITH_SELF_VERIFICATION)
3529 case CHAINING_CELL_BACKWARD_BRANCH:
3530 labelList[i].opCode =
3531 ARM_PSEUDO_CHAINING_CELL_BACKWARD_BRANCH;
3532 /* handle the codegen later */
3533 dvmInsertGrowableList(
3534 &chainingListByType[CHAINING_CELL_BACKWARD_BRANCH],
3535 (void *) i);
3536 break;
3537#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003538 default:
3539 break;
3540 }
3541 continue;
3542 }
Ben Chenge9695e52009-06-16 16:11:47 -07003543
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003544 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07003545
Ben Chengba4fc8b2009-06-01 13:00:29 -07003546 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
3547 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3548 InstructionFormat dalvikFormat =
3549 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003550 ArmLIR *boundaryLIR =
3551 newLIR2(cUnit, ARM_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
Ben Chenge9695e52009-06-16 16:11:47 -07003552 mir->offset,dalvikOpCode);
3553 /* Remember the first LIR for this block */
3554 if (headLIR == NULL) {
3555 headLIR = boundaryLIR;
3556 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003557 bool notHandled;
3558 /*
3559 * Debugging: screen the opcode first to see if it is in the
3560 * do[-not]-compile list
3561 */
3562 bool singleStepMe =
3563 gDvmJit.includeSelectedOp !=
3564 ((gDvmJit.opList[dalvikOpCode >> 3] &
3565 (1 << (dalvikOpCode & 0x7))) !=
3566 0);
Jeff Hao97319a82009-08-12 16:57:15 -07003567#if defined(WITH_SELF_VERIFICATION)
3568 /* Punt on opcodes we can't replay */
3569 if (selfVerificationPuntOps(dalvikOpCode))
3570 singleStepMe = true;
3571#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003572 if (singleStepMe || cUnit->allSingleStep) {
3573 notHandled = false;
3574 genInterpSingleStep(cUnit, mir);
3575 } else {
3576 opcodeCoverage[dalvikOpCode]++;
3577 switch (dalvikFormat) {
3578 case kFmt10t:
3579 case kFmt20t:
3580 case kFmt30t:
3581 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
3582 mir, blockList[i], labelList);
3583 break;
3584 case kFmt10x:
3585 notHandled = handleFmt10x(cUnit, mir);
3586 break;
3587 case kFmt11n:
3588 case kFmt31i:
3589 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
3590 break;
3591 case kFmt11x:
3592 notHandled = handleFmt11x(cUnit, mir);
3593 break;
3594 case kFmt12x:
3595 notHandled = handleFmt12x(cUnit, mir);
3596 break;
3597 case kFmt20bc:
3598 notHandled = handleFmt20bc(cUnit, mir);
3599 break;
3600 case kFmt21c:
3601 case kFmt31c:
3602 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
3603 break;
3604 case kFmt21h:
3605 notHandled = handleFmt21h(cUnit, mir);
3606 break;
3607 case kFmt21s:
3608 notHandled = handleFmt21s(cUnit, mir);
3609 break;
3610 case kFmt21t:
3611 notHandled = handleFmt21t(cUnit, mir, blockList[i],
3612 labelList);
3613 break;
3614 case kFmt22b:
3615 case kFmt22s:
3616 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
3617 break;
3618 case kFmt22c:
3619 notHandled = handleFmt22c(cUnit, mir);
3620 break;
3621 case kFmt22cs:
3622 notHandled = handleFmt22cs(cUnit, mir);
3623 break;
3624 case kFmt22t:
3625 notHandled = handleFmt22t(cUnit, mir, blockList[i],
3626 labelList);
3627 break;
3628 case kFmt22x:
3629 case kFmt32x:
3630 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
3631 break;
3632 case kFmt23x:
3633 notHandled = handleFmt23x(cUnit, mir);
3634 break;
3635 case kFmt31t:
3636 notHandled = handleFmt31t(cUnit, mir);
3637 break;
3638 case kFmt3rc:
3639 case kFmt35c:
3640 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
3641 labelList);
3642 break;
3643 case kFmt3rms:
3644 case kFmt35ms:
3645 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
3646 labelList);
3647 break;
3648 case kFmt3inline:
3649 notHandled = handleFmt3inline(cUnit, mir);
3650 break;
3651 case kFmt51l:
3652 notHandled = handleFmt51l(cUnit, mir);
3653 break;
3654 default:
3655 notHandled = true;
3656 break;
3657 }
3658 }
3659 if (notHandled) {
3660 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
3661 mir->offset,
3662 dalvikOpCode, getOpcodeName(dalvikOpCode),
3663 dalvikFormat);
3664 dvmAbort();
3665 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003666 }
3667 }
Ben Chenge9695e52009-06-16 16:11:47 -07003668 /* Eliminate redundant loads/stores and delay stores into later slots */
3669 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
3670 cUnit->lastLIRInsn);
Ben Cheng1efc9c52009-06-08 18:25:27 -07003671 /*
3672 * Check if the block is terminated due to trace length constraint -
3673 * insert an unconditional branch to the chaining cell.
3674 */
3675 if (blockList[i]->needFallThroughBranch) {
3676 genUnconditionalBranch(cUnit,
3677 &labelList[blockList[i]->fallThrough->id]);
3678 }
3679
Ben Chengba4fc8b2009-06-01 13:00:29 -07003680 }
3681
Ben Chenge9695e52009-06-16 16:11:47 -07003682 /* Handle the chaining cells in predefined order */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003683 for (i = 0; i < CHAINING_CELL_LAST; i++) {
3684 size_t j;
3685 int *blockIdList = (int *) chainingListByType[i].elemList;
3686
3687 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
3688
3689 /* No chaining cells of this type */
3690 if (cUnit->numChainingCells[i] == 0)
3691 continue;
3692
3693 /* Record the first LIR for a new type of chaining cell */
3694 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
3695
3696 for (j = 0; j < chainingListByType[i].numUsed; j++) {
3697 int blockId = blockIdList[j];
3698
3699 /* Align this chaining cell first */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003700 newLIR0(cUnit, ARM_PSEUDO_ALIGN4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003701
3702 /* Insert the pseudo chaining instruction */
3703 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
3704
3705
3706 switch (blockList[blockId]->blockType) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07003707 case CHAINING_CELL_NORMAL:
3708 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003709 blockList[blockId]->startOffset);
3710 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003711 case CHAINING_CELL_INVOKE_SINGLETON:
3712 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003713 blockList[blockId]->containingMethod);
3714 break;
Ben Cheng38329f52009-07-07 14:19:20 -07003715 case CHAINING_CELL_INVOKE_PREDICTED:
3716 handleInvokePredictedChainingCell(cUnit);
3717 break;
Ben Cheng1efc9c52009-06-08 18:25:27 -07003718 case CHAINING_CELL_HOT:
3719 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07003720 blockList[blockId]->startOffset);
3721 break;
Jeff Hao97319a82009-08-12 16:57:15 -07003722#if defined(WITH_SELF_VERIFICATION)
3723 case CHAINING_CELL_BACKWARD_BRANCH:
3724 handleBackwardBranchChainingCell(cUnit,
3725 blockList[blockId]->startOffset);
3726 break;
3727#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003728 default:
3729 dvmAbort();
3730 break;
3731 }
3732 }
3733 }
Ben Chenge9695e52009-06-16 16:11:47 -07003734
3735 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003736}
3737
3738/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07003739bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003740{
Bill Buzbee716f1202009-07-23 13:22:09 -07003741 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003742
3743 if (gDvmJit.codeCacheFull) {
Bill Buzbee716f1202009-07-23 13:22:09 -07003744 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003745 }
3746
3747 switch (work->kind) {
3748 case kWorkOrderMethod:
Bill Buzbee716f1202009-07-23 13:22:09 -07003749 res = dvmCompileMethod(work->info, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003750 break;
3751 case kWorkOrderTrace:
Ben Cheng1efc9c52009-06-08 18:25:27 -07003752 /* Start compilation with maximally allowed trace length */
Bill Buzbee716f1202009-07-23 13:22:09 -07003753 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003754 break;
3755 default:
Bill Buzbee716f1202009-07-23 13:22:09 -07003756 res = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003757 dvmAbort();
3758 }
3759 return res;
3760}
3761
Ben Chengba4fc8b2009-06-01 13:00:29 -07003762/* Architectural-specific debugging helpers go here */
3763void dvmCompilerArchDump(void)
3764{
3765 /* Print compiled opcode in this VM instance */
3766 int i, start, streak;
3767 char buf[1024];
3768
3769 streak = i = 0;
3770 buf[0] = 0;
3771 while (opcodeCoverage[i] == 0 && i < 256) {
3772 i++;
3773 }
3774 if (i == 256) {
3775 return;
3776 }
3777 for (start = i++, streak = 1; i < 256; i++) {
3778 if (opcodeCoverage[i]) {
3779 streak++;
3780 } else {
3781 if (streak == 1) {
3782 sprintf(buf+strlen(buf), "%x,", start);
3783 } else {
3784 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
3785 }
3786 streak = 0;
3787 while (opcodeCoverage[i] == 0 && i < 256) {
3788 i++;
3789 }
3790 if (i < 256) {
3791 streak = 1;
3792 start = i;
3793 }
3794 }
3795 }
3796 if (streak) {
3797 if (streak == 1) {
3798 sprintf(buf+strlen(buf), "%x", start);
3799 } else {
3800 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
3801 }
3802 }
3803 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07003804 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003805 }
3806}