blob: 6f28d33df1424aa189d64bc2a5593bf7111e3f7d [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Bill Buzbee50a6bf22009-07-08 13:08:04 -070017/*
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
Ben Cheng4238ec22009-08-24 16:32:22 -070027#include "compiler/Loop.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070028
Ben Chengba4fc8b2009-06-01 13:00:29 -070029/* Array holding the entry offset of each template relative to the first one */
30static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
31
32/* Track exercised opcodes */
33static int opcodeCoverage[256];
34
Jeff Hao97319a82009-08-12 16:57:15 -070035#if defined(WITH_SELF_VERIFICATION)
36/* Prevent certain opcodes from being jitted */
37static inline bool selfVerificationPuntOps(OpCode op)
38{
39 return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT ||
40 op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY);
41}
42
43/*
44 * The following are used to keep compiled loads and stores from modifying
45 * memory during self verification mode.
46 *
47 * Stores do not modify memory. Instead, the address and value pair are stored
48 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
49 * than a word, the word containing the address is loaded first before being
50 * updated.
51 *
52 * Loads check heapSpace first and return data from there if an entry exists.
53 * Otherwise, data is loaded from memory as usual.
54 */
55
56/* Decode contents of heapArgSpace to determine addr to load from */
57static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
58{
Bill Buzbee1465db52009-09-23 17:17:35 -070059 int reg = heapArgSpace->regMap & 0xFF;
60 if (!FPREG(reg)) {
61 assert(reg < 16);
62 *addr = heapArgSpace->coreRegs[reg];
63 } else {
64 assert(!DOUBLEREG(reg));
65 *addr = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
Jeff Hao97319a82009-08-12 16:57:15 -070066 }
67}
68
69/* Decode contents of heapArgSpace to determine reg to load into */
70static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
71 int data, int reg)
72{
Bill Buzbee1465db52009-09-23 17:17:35 -070073 if (!FPREG(reg)) {
74 assert(reg < 16);
75 heapArgSpace->coreRegs[reg] = data;
76 } else {
77 assert(!DOUBLEREG(reg));
78 heapArgSpace->fpRegs[(reg & FP_REG_MASK)] = data;
Jeff Hao97319a82009-08-12 16:57:15 -070079 }
80}
81
82static void selfVerificationLoad(InterpState* interpState)
83{
84 Thread *self = dvmThreadSelf();
85 ShadowHeap *heapSpacePtr;
86 ShadowSpace *shadowSpace = self->shadowSpace;
87 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
88
89 int addr, data;
90 selfVerificationLoadDecode(heapArgSpace, &addr);
91
92 for (heapSpacePtr = shadowSpace->heapSpace;
93 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
94 if (heapSpacePtr->addr == addr) {
95 data = heapSpacePtr->data;
96 break;
97 }
98 }
99
100 if (heapSpacePtr == shadowSpace->heapSpaceTail)
101 data = *((unsigned int*) addr);
102
Bill Buzbee1465db52009-09-23 17:17:35 -0700103 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Ben Chengd7d426a2009-09-22 11:23:36 -0700104
Bill Buzbee1465db52009-09-23 17:17:35 -0700105 // LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
Ben Chengd7d426a2009-09-22 11:23:36 -0700106
Jeff Hao97319a82009-08-12 16:57:15 -0700107 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
108}
109
110static void selfVerificationLoadByte(InterpState* interpState)
111{
112 Thread *self = dvmThreadSelf();
113 ShadowHeap *heapSpacePtr;
114 ShadowSpace *shadowSpace = self->shadowSpace;
115 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
116
117 int addr, data;
118 selfVerificationLoadDecode(heapArgSpace, &addr);
119
120 int maskedAddr = addr & 0xFFFFFFFC;
121 int alignment = addr & 0x3;
122
123 for (heapSpacePtr = shadowSpace->heapSpace;
124 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
125 if (heapSpacePtr->addr == maskedAddr) {
126 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
127 data = *((unsigned char*) addr);
128 break;
129 }
130 }
131
132 if (heapSpacePtr == shadowSpace->heapSpaceTail)
133 data = *((unsigned char*) addr);
134
135 //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
136
Bill Buzbee1465db52009-09-23 17:17:35 -0700137 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700138 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
139}
140
141static void selfVerificationLoadHalfword(InterpState* interpState)
142{
143 Thread *self = dvmThreadSelf();
144 ShadowHeap *heapSpacePtr;
145 ShadowSpace *shadowSpace = self->shadowSpace;
146 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
147
148 int addr, data;
149 selfVerificationLoadDecode(heapArgSpace, &addr);
150
151 int maskedAddr = addr & 0xFFFFFFFC;
152 int alignment = addr & 0x2;
153
154 for (heapSpacePtr = shadowSpace->heapSpace;
155 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
156 if (heapSpacePtr->addr == maskedAddr) {
157 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
158 data = *((unsigned short*) addr);
159 break;
160 }
161 }
162
163 if (heapSpacePtr == shadowSpace->heapSpaceTail)
164 data = *((unsigned short*) addr);
165
Bill Buzbee1465db52009-09-23 17:17:35 -0700166 //LOGD("*** HEAP LOAD kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700167
Bill Buzbee1465db52009-09-23 17:17:35 -0700168 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700169 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
170}
171
172static void selfVerificationLoadSignedByte(InterpState* interpState)
173{
174 Thread *self = dvmThreadSelf();
175 ShadowHeap* heapSpacePtr;
176 ShadowSpace* shadowSpace = self->shadowSpace;
177 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
178
179 int addr, data;
180 selfVerificationLoadDecode(heapArgSpace, &addr);
181
182 int maskedAddr = addr & 0xFFFFFFFC;
183 int alignment = addr & 0x3;
184
185 for (heapSpacePtr = shadowSpace->heapSpace;
186 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
187 if (heapSpacePtr->addr == maskedAddr) {
188 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
189 data = *((signed char*) addr);
190 break;
191 }
192 }
193
194 if (heapSpacePtr == shadowSpace->heapSpaceTail)
195 data = *((signed char*) addr);
196
197 //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
198
Bill Buzbee1465db52009-09-23 17:17:35 -0700199 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700200 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
201}
202
203static void selfVerificationLoadSignedHalfword(InterpState* interpState)
204{
205 Thread *self = dvmThreadSelf();
206 ShadowHeap* heapSpacePtr;
207 ShadowSpace* shadowSpace = self->shadowSpace;
208 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
209
210 int addr, data;
211 selfVerificationLoadDecode(heapArgSpace, &addr);
212
213 int maskedAddr = addr & 0xFFFFFFFC;
214 int alignment = addr & 0x2;
215
216 for (heapSpacePtr = shadowSpace->heapSpace;
217 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
218 if (heapSpacePtr->addr == maskedAddr) {
219 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
220 data = *((signed short*) addr);
221 break;
222 }
223 }
224
225 if (heapSpacePtr == shadowSpace->heapSpaceTail)
226 data = *((signed short*) addr);
227
Bill Buzbee1465db52009-09-23 17:17:35 -0700228 //LOGD("*** HEAP LOAD SIGNED kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700229
Bill Buzbee1465db52009-09-23 17:17:35 -0700230 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700231 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
232}
233
234static void selfVerificationLoadDoubleword(InterpState* interpState)
235{
236 Thread *self = dvmThreadSelf();
237 ShadowHeap* heapSpacePtr;
238 ShadowSpace* shadowSpace = self->shadowSpace;
239 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
240
241 int addr;
242 selfVerificationLoadDecode(heapArgSpace, &addr);
243
244 int addr2 = addr+4;
245 unsigned int data = *((unsigned int*) addr);
246 unsigned int data2 = *((unsigned int*) addr2);
247
248 for (heapSpacePtr = shadowSpace->heapSpace;
249 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
250 if (heapSpacePtr->addr == addr) {
251 data = heapSpacePtr->data;
252 } else if (heapSpacePtr->addr == addr2) {
253 data2 = heapSpacePtr->data;
254 }
255 }
256
Bill Buzbee1465db52009-09-23 17:17:35 -0700257 // LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
Jeff Hao97319a82009-08-12 16:57:15 -0700258 // addr, data, data2);
259
Bill Buzbee1465db52009-09-23 17:17:35 -0700260 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
261 int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700262 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
263 selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
264}
265
266/* Decode contents of heapArgSpace to determine arguments to store. */
267static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
268 int* value, int reg)
269{
Bill Buzbee1465db52009-09-23 17:17:35 -0700270 if (!FPREG(reg)) {
271 assert(reg < 16);
272 *value = heapArgSpace->coreRegs[reg];
273 } else {
274 assert(!DOUBLEREG(reg));
275 *value = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
Jeff Hao97319a82009-08-12 16:57:15 -0700276 }
277}
278
279static void selfVerificationStore(InterpState* interpState)
280{
281 Thread *self = dvmThreadSelf();
282 ShadowHeap *heapSpacePtr;
283 ShadowSpace *shadowSpace = self->shadowSpace;
284 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
285
286 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700287 int reg0 = heapArgSpace->regMap & 0xFF;
288 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700289 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
290 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
291
292 //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
293
294 for (heapSpacePtr = shadowSpace->heapSpace;
295 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
296 if (heapSpacePtr->addr == addr) break;
297 }
298
299 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
300 heapSpacePtr->addr = addr;
301 shadowSpace->heapSpaceTail++;
302 }
303
304 heapSpacePtr->data = data;
305}
306
307static void selfVerificationStoreByte(InterpState* interpState)
308{
309 Thread *self = dvmThreadSelf();
310 ShadowHeap *heapSpacePtr;
311 ShadowSpace *shadowSpace = self->shadowSpace;
312 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
313
314 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700315 int reg0 = heapArgSpace->regMap & 0xFF;
316 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700317 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
318 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
319
320 int maskedAddr = addr & 0xFFFFFFFC;
321 int alignment = addr & 0x3;
322
323 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
324
325 for (heapSpacePtr = shadowSpace->heapSpace;
326 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
327 if (heapSpacePtr->addr == maskedAddr) break;
328 }
329
330 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
331 heapSpacePtr->addr = maskedAddr;
332 heapSpacePtr->data = *((unsigned int*) maskedAddr);
333 shadowSpace->heapSpaceTail++;
334 }
335
336 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
337 *((unsigned char*) addr) = (char) data;
338
339 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
340 // addr, heapSpacePtr->data);
341}
342
343static void selfVerificationStoreHalfword(InterpState* interpState)
344{
345 Thread *self = dvmThreadSelf();
346 ShadowHeap *heapSpacePtr;
347 ShadowSpace *shadowSpace = self->shadowSpace;
348 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
349
350 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700351 int reg0 = heapArgSpace->regMap & 0xFF;
352 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700353 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
354 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
355
356 int maskedAddr = addr & 0xFFFFFFFC;
357 int alignment = addr & 0x2;
358
Bill Buzbee1465db52009-09-23 17:17:35 -0700359 //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700360
361 for (heapSpacePtr = shadowSpace->heapSpace;
362 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
363 if (heapSpacePtr->addr == maskedAddr) break;
364 }
365
366 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
367 heapSpacePtr->addr = maskedAddr;
368 heapSpacePtr->data = *((unsigned int*) maskedAddr);
369 shadowSpace->heapSpaceTail++;
370 }
371
372 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
373 *((unsigned short*) addr) = (short) data;
374
Bill Buzbee1465db52009-09-23 17:17:35 -0700375 //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Final Data: 0x%x",
Jeff Hao97319a82009-08-12 16:57:15 -0700376 // addr, heapSpacePtr->data);
377}
378
379static void selfVerificationStoreDoubleword(InterpState* interpState)
380{
381 Thread *self = dvmThreadSelf();
382 ShadowHeap *heapSpacePtr;
383 ShadowSpace *shadowSpace = self->shadowSpace;
384 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
385
386 int addr, data, data2;
Bill Buzbee1465db52009-09-23 17:17:35 -0700387 int reg0 = heapArgSpace->regMap & 0xFF;
388 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
389 int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700390 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
391 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
392 selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
393
394 int addr2 = addr+4;
395 bool store1 = false, store2 = false;
396
397 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
398 // addr, data, data2);
399
400 for (heapSpacePtr = shadowSpace->heapSpace;
401 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
402 if (heapSpacePtr->addr == addr) {
403 heapSpacePtr->data = data;
404 store1 = true;
405 } else if (heapSpacePtr->addr == addr2) {
406 heapSpacePtr->data = data2;
407 store2 = true;
408 }
409 }
410
411 if (!store1) {
412 shadowSpace->heapSpaceTail->addr = addr;
413 shadowSpace->heapSpaceTail->data = data;
414 shadowSpace->heapSpaceTail++;
415 }
416 if (!store2) {
417 shadowSpace->heapSpaceTail->addr = addr2;
418 shadowSpace->heapSpaceTail->data = data2;
419 shadowSpace->heapSpaceTail++;
420 }
421}
422
423/* Common wrapper function for all memory operations */
424static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
425 void* funct)
426{
Bill Buzbee1465db52009-09-23 17:17:35 -0700427 /* push r0 and r7 to give us a foothold */
428 newLIR1(cUnit, kThumbPush, (1 << r0) | (1 << r7));
Jeff Hao97319a82009-08-12 16:57:15 -0700429
Bill Buzbee1465db52009-09-23 17:17:35 -0700430 /* Let the save handler know where the save record is */
431 loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace));
Jeff Hao97319a82009-08-12 16:57:15 -0700432
Bill Buzbee1465db52009-09-23 17:17:35 -0700433 /* Load the regMap and call the save handler [note: handler pops r0/r7] */
434 loadConstant(cUnit, r7, regMap);
435 genDispatchToHandler(cUnit, TEMPLATE_SAVE_STATE);
Jeff Hao97319a82009-08-12 16:57:15 -0700436
Bill Buzbee1465db52009-09-23 17:17:35 -0700437 /* Set function pointer, pass rGLUE and branch */
Jeff Hao97319a82009-08-12 16:57:15 -0700438 loadConstant(cUnit, r1, (int) funct);
Bill Buzbee1465db52009-09-23 17:17:35 -0700439 newLIR2(cUnit, kThumbMovRR, r0, rGLUE);
440 newLIR1(cUnit, kThumbBlxR, r1);
Jeff Hao97319a82009-08-12 16:57:15 -0700441
Bill Buzbee1465db52009-09-23 17:17:35 -0700442 /* Let the recover handler know where coreRegs[0] and restore regs */
443 loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace) +
444 offsetof(HeapArgSpace, coreRegs));
445 genDispatchToHandler(cUnit, TEMPLATE_RESTORE_STATE);
Jeff Hao97319a82009-08-12 16:57:15 -0700446}
447#endif
448
Ben Chengba4fc8b2009-06-01 13:00:29 -0700449/*
Bill Buzbee1465db52009-09-23 17:17:35 -0700450 * Load a Dalvik register into a physical register. Take care when
451 * using this routine, as it doesn't perform any bookkeeping regarding
452 * register liveness. That is the responsibility of the caller.
453 */
454static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
455 int reg1)
456{
457 rlSrc = updateLoc(cUnit, rlSrc); /* Is our value hiding in a live temp? */
458 if (rlSrc.location == kLocPhysReg) {
459 genRegCopy(cUnit, reg1, rlSrc.lowReg);
460 } else if (rlSrc.location == kLocRetval) {
461 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), reg1);
462 } else {
463 assert(rlSrc.location == kLocDalvikFrame);
464 loadWordDisp(cUnit, rFP, sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
465 reg1);
466 }
467}
468
469/*
470 * Similar to loadValueDirect, but clobbers and allocates the target
471 * register. Should be used when loading to a fixed register (for example,
472 * loading arguments to an out of line call.
473 */
474static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
475 int reg1)
476{
477 clobberReg(cUnit, reg1);
478 markRegInUse(cUnit, reg1);
479 loadValueDirect(cUnit, rlSrc, reg1);
480}
481
482/*
483 * Load a Dalvik register pair into a physical register[s]. Take care when
484 * using this routine, as it doesn't perform any bookkeeping regarding
485 * register liveness. That is the responsibility of the caller.
486 */
487static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
488 int regLo, int regHi)
489{
490 rlSrc = updateLocWide(cUnit, rlSrc);
491 if (rlSrc.location == kLocPhysReg) {
492 genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
493 } else if (rlSrc.location == kLocRetval) {
494 loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
495 regLo, regHi, false, INVALID_SREG);
496 } else {
497 assert(rlSrc.location == kLocDalvikFrame);
498 loadBaseDispWide(cUnit, NULL, rFP,
499 sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
500 regLo, regHi, false, INVALID_SREG);
501 }
502}
503
504/*
505 * Similar to loadValueDirect, but clobbers and allocates the target
506 * registers. Should be used when loading to a fixed registers (for example,
507 * loading arguments to an out of line call.
508 */
509static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
510 int regLo, int regHi)
511{
512 clobberReg(cUnit, regLo);
513 clobberReg(cUnit, regHi);
514 markRegInUse(cUnit, regLo);
515 markRegInUse(cUnit, regHi);
516 loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
517}
518
519static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
520 RegisterClass opKind)
521{
522 RegisterInfo *pReg;
523 rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
524 if (rlSrc.location == kLocDalvikFrame) {
525 loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
526 rlSrc.location = kLocPhysReg;
527 markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
528 } else if (rlSrc.location == kLocRetval) {
529 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg);
530 rlSrc.location = kLocPhysReg;
531 clobberReg(cUnit, rlSrc.lowReg);
532 }
533 return rlSrc;
534}
535
536static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
537 RegisterClass opKind)
538{
539 RegisterInfo *pRegLo;
540 RegisterInfo *pRegHi;
541 assert(rlSrc.wide);
542 rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
543 if (rlSrc.location == kLocDalvikFrame) {
544 loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
545 rlSrc.location = kLocPhysReg;
546 markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
547 markRegLive(cUnit, rlSrc.highReg, hiSReg(rlSrc.sRegLow));
548 } else if (rlSrc.location == kLocRetval) {
549 loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
550 rlSrc.lowReg, rlSrc.highReg, false, INVALID_SREG);
551 rlSrc.location = kLocPhysReg;
552 clobberReg(cUnit, rlSrc.lowReg);
553 clobberReg(cUnit, rlSrc.highReg);
554 }
555 return rlSrc;
556}
557
558static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
559 RegLocation rlSrc)
560{
561 RegisterInfo *pRegLo;
562 LIR *defStart;
563 LIR *defEnd;
564 assert(!rlDest.wide);
565 assert(!rlSrc.wide);
566 killNullCheckedLocation(cUnit, rlDest);
567 rlSrc = updateLoc(cUnit, rlSrc);
568 rlDest = updateLoc(cUnit, rlDest);
569 if (rlSrc.location == kLocPhysReg) {
570 if (isLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) {
571 // Src is live or Dest has assigned reg.
572 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
573 genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
574 } else {
575 // Just re-assign the registers. Dest gets Src's regs
576 rlDest.lowReg = rlSrc.lowReg;
577 clobberReg(cUnit, rlSrc.lowReg);
578 }
579 } else {
580 // Load Src either into promoted Dest or temps allocated for Dest
581 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
582 loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
583 }
584
585 // Dest is now live and dirty (until/if we flush it to home location)
586 markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
587 markRegDirty(cUnit, rlDest.lowReg);
588
589
590 if (rlDest.location == kLocRetval) {
591 storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
592 rlDest.lowReg, kWord);
593 clobberReg(cUnit, rlDest.lowReg);
594 } else {
595 resetDefLoc(cUnit, rlDest);
596 if (liveOut(cUnit, rlDest.sRegLow)) {
597 defStart = (LIR *)cUnit->lastLIRInsn;
598 int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
599 storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
600 markRegClean(cUnit, rlDest.lowReg);
601 defEnd = (LIR *)cUnit->lastLIRInsn;
602 markDef(cUnit, rlDest, defStart, defEnd);
603 }
604 }
605}
606
607static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
608 RegLocation rlSrc)
609{
610 RegisterInfo *pRegLo;
611 RegisterInfo *pRegHi;
612 LIR *defStart;
613 LIR *defEnd;
614 bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
615 assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
616 assert(rlDest.wide);
617 assert(rlSrc.wide);
618 killNullCheckedLocation(cUnit, rlDest);
619 if (rlSrc.location == kLocPhysReg) {
620 if (isLive(cUnit, rlSrc.lowReg) || isLive(cUnit, rlSrc.highReg) ||
621 (rlDest.location == kLocPhysReg)) {
622 // Src is live or Dest has assigned reg.
623 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
624 genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
625 rlSrc.lowReg, rlSrc.highReg);
626 } else {
627 // Just re-assign the registers. Dest gets Src's regs
628 rlDest.lowReg = rlSrc.lowReg;
629 rlDest.highReg = rlSrc.highReg;
630 clobberReg(cUnit, rlSrc.lowReg);
631 clobberReg(cUnit, rlSrc.highReg);
632 }
633 } else {
634 // Load Src either into promoted Dest or temps allocated for Dest
635 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
636 loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
637 rlDest.highReg);
638 }
639
640 // Dest is now live and dirty (until/if we flush it to home location)
641 markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
642 markRegLive(cUnit, rlDest.highReg, hiSReg(rlDest.sRegLow));
643 markRegDirty(cUnit, rlDest.lowReg);
644 markRegDirty(cUnit, rlDest.highReg);
645 markRegPair(cUnit, rlDest.lowReg, rlDest.highReg);
646
647
648 if (rlDest.location == kLocRetval) {
649 storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval),
650 rlDest.lowReg, rlDest.highReg);
651 clobberReg(cUnit, rlDest.lowReg);
652 clobberReg(cUnit, rlDest.highReg);
653 } else {
654 resetDefLocWide(cUnit, rlDest);
655 if (liveOut(cUnit, rlDest.sRegLow) ||
656 liveOut(cUnit, hiSReg(rlDest.sRegLow))) {
657 defStart = (LIR *)cUnit->lastLIRInsn;
658 int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
659 assert((vReg+1) == sReg2vReg(cUnit, hiSReg(rlDest.sRegLow)));
660 storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
661 rlDest.highReg);
662 markRegClean(cUnit, rlDest.lowReg);
663 markRegClean(cUnit, rlDest.highReg);
664 defEnd = (LIR *)cUnit->lastLIRInsn;
665 markDefWide(cUnit, rlDest, defStart, defEnd);
666 }
667 }
668}
669
670/*
671 * Load an immediate value into a fixed or temp register. Target
672 * register is clobbered, and marked inUse.
673 */
674static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
675{
676 if (isTemp(cUnit, rDest)) {
677 clobberReg(cUnit, rDest);
678 markRegInUse(cUnit, rDest);
679 }
680 return loadConstantValue(cUnit, rDest, value);
681}
682
683/*
Ben Chengd7d426a2009-09-22 11:23:36 -0700684 * Mark load/store instructions that access Dalvik registers through rFP +
685 * offset.
686 */
687static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
688{
689 if (isLoad) {
690 lir->useMask |= ENCODE_DALVIK_REG;
691 } else {
692 lir->defMask |= ENCODE_DALVIK_REG;
693 }
694
695 /*
696 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
697 * access.
698 */
699 lir->aliasInfo = regId;
700 if (DOUBLEREG(lir->operands[0])) {
701 lir->aliasInfo |= 0x80000000;
702 }
703}
704
705/*
706 * Decode the register id and mark the corresponding bit(s).
707 */
708static inline void setupRegMask(u8 *mask, int reg)
709{
710 u8 seed;
711 int shift;
712 int regId = reg & 0x1f;
713
714 /*
715 * Each double register is equal to a pair of single-precision FP registers
716 */
717 seed = DOUBLEREG(reg) ? 3 : 1;
718 /* FP register starts at bit position 16 */
719 shift = FPREG(reg) ? kFPReg0 : 0;
720 /* Expand the double register id into single offset */
721 shift += regId;
722 *mask |= seed << shift;
723}
724
725/*
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700726 * Set up the proper fields in the resource mask
727 */
728static void setupResourceMasks(ArmLIR *lir)
729{
730 int opCode = lir->opCode;
731 int flags;
732
733 if (opCode <= 0) {
734 lir->useMask = lir->defMask = 0;
735 return;
736 }
737
738 flags = EncodingMap[lir->opCode].flags;
739
740 /* Set up the mask for resources that are updated */
741 if (flags & IS_BRANCH) {
742 lir->defMask |= ENCODE_REG_PC;
Ben Chengd7d426a2009-09-22 11:23:36 -0700743 lir->useMask |= ENCODE_REG_PC;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700744 }
745
746 if (flags & REG_DEF0) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700747 setupRegMask(&lir->defMask, lir->operands[0]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700748 }
749
750 if (flags & REG_DEF1) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700751 setupRegMask(&lir->defMask, lir->operands[1]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700752 }
753
754 if (flags & REG_DEF_SP) {
755 lir->defMask |= ENCODE_REG_SP;
756 }
757
Ben Chengd7d426a2009-09-22 11:23:36 -0700758 if (flags & REG_DEF_SP) {
759 lir->defMask |= ENCODE_REG_LR;
760 }
761
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700762 if (flags & REG_DEF_LIST0) {
763 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
764 }
765
766 if (flags & REG_DEF_LIST1) {
767 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
768 }
769
770 if (flags & SETS_CCODES) {
771 lir->defMask |= ENCODE_CCODE;
772 }
773
774 /* Conservatively treat the IT block */
775 if (flags & IS_IT) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700776 lir->defMask = ENCODE_ALL;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700777 }
778
779 /* Set up the mask for resources that are used */
780 if (flags & IS_BRANCH) {
781 lir->useMask |= ENCODE_REG_PC;
782 }
783
Bill Buzbee1465db52009-09-23 17:17:35 -0700784 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700785 int i;
786
Bill Buzbee1465db52009-09-23 17:17:35 -0700787 for (i = 0; i < 4; i++) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700788 if (flags & (1 << (kRegUse0 + i))) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700789 setupRegMask(&lir->useMask, lir->operands[i]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700790 }
791 }
792 }
793
794 if (flags & REG_USE_PC) {
795 lir->useMask |= ENCODE_REG_PC;
796 }
797
798 if (flags & REG_USE_SP) {
799 lir->useMask |= ENCODE_REG_SP;
800 }
801
802 if (flags & REG_USE_LIST0) {
803 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
804 }
805
806 if (flags & REG_USE_LIST1) {
807 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
808 }
809
810 if (flags & USES_CCODES) {
811 lir->useMask |= ENCODE_CCODE;
812 }
813}
814
815/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700816 * The following are building blocks to construct low-level IRs with 0 - 4
Ben Chengba4fc8b2009-06-01 13:00:29 -0700817 * operands.
818 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700819static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700820{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700821 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700822 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700823 insn->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700824 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700825 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
826 return insn;
827}
828
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700829static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700830 int dest)
831{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700832 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700833 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700834 insn->opCode = opCode;
835 insn->operands[0] = dest;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700836 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700837 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
838 return insn;
839}
840
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700841static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700842 int dest, int src1)
843{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700844 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700845 assert(isPseudoOpCode(opCode) ||
846 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847 insn->opCode = opCode;
848 insn->operands[0] = dest;
849 insn->operands[1] = src1;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700850 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700851 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
852 return insn;
853}
854
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700855static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700856 int dest, int src1, int src2)
857{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700858 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700859 if (!(EncodingMap[opCode].flags & IS_TERTIARY_OP)) {
860 LOGE("Bad LIR3: %s[%d]",EncodingMap[opCode].name,opCode);
861 }
Ben Chenge9695e52009-06-16 16:11:47 -0700862 assert(isPseudoOpCode(opCode) ||
863 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700864 insn->opCode = opCode;
865 insn->operands[0] = dest;
866 insn->operands[1] = src1;
867 insn->operands[2] = src2;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700868 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700869 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
870 return insn;
871}
872
Bill Buzbee270c1d62009-08-13 16:58:07 -0700873static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
874 int dest, int src1, int src2, int info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700875{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700876 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
877 assert(isPseudoOpCode(opCode) ||
878 (EncodingMap[opCode].flags & IS_QUAD_OP));
879 insn->opCode = opCode;
880 insn->operands[0] = dest;
881 insn->operands[1] = src1;
882 insn->operands[2] = src2;
883 insn->operands[3] = info;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700884 setupResourceMasks(insn);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700885 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
886 return insn;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700887}
888
Ben Chengba4fc8b2009-06-01 13:00:29 -0700889/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700890 * If the next instruction is a move-result or move-result-long,
Bill Buzbee1465db52009-09-23 17:17:35 -0700891 * return the target Dalvik sReg[s] and convert the next to a
892 * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700893 */
Bill Buzbee1465db52009-09-23 17:17:35 -0700894static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
895 bool fpHint)
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700896{
897 if (mir->next &&
898 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
Bill Buzbee1465db52009-09-23 17:17:35 -0700899 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700900 mir->next->dalvikInsn.opCode = OP_NOP;
Bill Buzbee1465db52009-09-23 17:17:35 -0700901 return getDestLoc(cUnit, mir->next, 0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700902 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700903 RegLocation res = LOC_DALVIK_RETURN_VAL;
904 res.fp = fpHint;
905 return res;
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700906 }
907}
908
Bill Buzbee1465db52009-09-23 17:17:35 -0700909static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
910 bool fpHint)
911{
912 if (mir->next &&
913 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
914 mir->next->dalvikInsn.opCode = OP_NOP;
915 return getDestLocWide(cUnit, mir->next, 0, 1);
916 } else {
917 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
918 res.fp = fpHint;
919 return res;
920 }
921}
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700922
923/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700924 * The following are building blocks to insert constants into the pool or
925 * instruction streams.
926 */
927
928/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700929static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700930{
931 /* Add the constant to the literal pool */
932 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700933 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700934 newValue->operands[0] = value;
935 newValue->generic.next = cUnit->wordList;
936 cUnit->wordList = (LIR *) newValue;
937 return newValue;
938 } else {
939 /* Add the constant in the middle of code stream */
Bill Buzbee1465db52009-09-23 17:17:35 -0700940 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
941 newLIR1(cUnit, kArm16BitData, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700942 }
943 return NULL;
944}
945
946/*
947 * Search the existing constants in the literal pool for an exact or close match
948 * within specified delta (greater or equal to 0).
949 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700950static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700951 unsigned int delta)
952{
953 LIR *dataTarget = cUnit->wordList;
954 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700955 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700956 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700957 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700958 dataTarget = dataTarget->next;
959 }
960 return NULL;
961}
962
Ben Chengba4fc8b2009-06-01 13:00:29 -0700963/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700964static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
965 ArmLIR *branch,
966 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700967{
968 /* Set up the place holder to reconstruct this Dalvik PC */
969 if (pcrLabel == NULL) {
970 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700971 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700972 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700973 pcrLabel->operands[0] = dPC;
974 pcrLabel->operands[1] = dOffset;
975 /* Insert the place holder to the growable list */
976 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
977 }
978 /* Branch to the PC reconstruction code */
979 branch->generic.target = (LIR *) pcrLabel;
980 return pcrLabel;
981}
982
Ben Chengba4fc8b2009-06-01 13:00:29 -0700983
984/*
985 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
986 * satisfies.
987 */
Ben Cheng0fd31e42009-09-03 14:40:16 -0700988static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
989 ArmConditionCode cond,
990 int reg1, int reg2, int dOffset,
991 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700992{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700993 ArmLIR *res;
Bill Buzbee1465db52009-09-23 17:17:35 -0700994 res = opRegReg(cUnit, kOpCmp, reg1, reg2);
Ben Cheng4f489172009-09-27 17:08:35 -0700995 ArmLIR *branch = opCondBranch(cUnit, cond);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700996 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
997 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700998}
999
Ben Chenge9695e52009-06-16 16:11:47 -07001000/*
Bill Buzbee1465db52009-09-23 17:17:35 -07001001 * Perform null-check on a register. sReg is the ssa register being checked,
Ben Chenge9695e52009-06-16 16:11:47 -07001002 * and mReg is the machine register holding the actual value. If internal state
Bill Buzbee1465db52009-09-23 17:17:35 -07001003 * indicates that sReg has been checked before the check request is ignored.
Ben Chenge9695e52009-06-16 16:11:47 -07001004 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001005static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001006 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001007{
Ben Chenge9695e52009-06-16 16:11:47 -07001008 /* This particular Dalvik register has been null-checked */
Bill Buzbee1465db52009-09-23 17:17:35 -07001009 if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
Ben Chenge9695e52009-06-16 16:11:47 -07001010 return pcrLabel;
1011 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001012 dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
1013 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
Ben Chenge9695e52009-06-16 16:11:47 -07001014}
1015
1016/*
1017 * Perform zero-check on a register. Similar to genNullCheck but the value being
1018 * checked does not have a corresponding Dalvik register.
1019 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001020static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
1021 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -07001022{
Bill Buzbee1465db52009-09-23 17:17:35 -07001023 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001024}
1025
1026/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001027static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
1028 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001029{
Bill Buzbee1465db52009-09-23 17:17:35 -07001030 return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001031 pcrLabel);
1032}
1033
1034/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001035static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
1036 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001037{
Bill Buzbee1465db52009-09-23 17:17:35 -07001038 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001039 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
1040}
1041
1042/* Load a wide field from an object instance */
1043static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
1044{
1045 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001046 RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
1047 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
1048 RegLocation rlResult;
1049 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1050 int regPtr = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001051
Bill Buzbee1465db52009-09-23 17:17:35 -07001052 assert(rlDest.wide);
Ben Chenge9695e52009-06-16 16:11:47 -07001053
Bill Buzbee1465db52009-09-23 17:17:35 -07001054 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1055 NULL);/* null object? */
1056 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1057 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Jeff Hao97319a82009-08-12 16:57:15 -07001058#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001059 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07001060#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001061 int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001062 selfVerificationMemOpWrapper(cUnit, regMap,
1063 &selfVerificationLoadDoubleword);
Jeff Hao97319a82009-08-12 16:57:15 -07001064#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001065 freeTemp(cUnit, regPtr);
1066 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001067}
1068
1069/* Store a wide field to an object instance */
1070static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
1071{
1072 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001073 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1074 RegLocation rlObj = getSrcLoc(cUnit, mir, 2);
1075 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1076 int regPtr;
1077 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1078 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1079 NULL);/* null object? */
1080 regPtr = allocTemp(cUnit);
1081 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001082#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001083 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07001084#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001085 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001086 selfVerificationMemOpWrapper(cUnit, regMap,
1087 &selfVerificationStoreDoubleword);
1088#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001089 freeTemp(cUnit, regPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001090}
1091
1092/*
1093 * Load a field from an object instance
1094 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001095 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001096static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001097 int fieldOffset)
1098{
Bill Buzbee1465db52009-09-23 17:17:35 -07001099 int regPtr;
1100 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001101 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001102 RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
1103 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
1104 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1105 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Jeff Hao97319a82009-08-12 16:57:15 -07001106#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001107 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
1108 size, true, rlObj.sRegLow);
Jeff Hao97319a82009-08-12 16:57:15 -07001109#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001110 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1111 NULL);/* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -07001112 /* Combine address and offset */
Bill Buzbee1465db52009-09-23 17:17:35 -07001113 regPtr = allocTemp(cUnit);
1114 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001115
Bill Buzbee1465db52009-09-23 17:17:35 -07001116 int regMap = rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001117 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
Bill Buzbee1465db52009-09-23 17:17:35 -07001118 freeTemp(cUnit, regPtr);
Jeff Hao97319a82009-08-12 16:57:15 -07001119#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001120 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001121}
1122
1123/*
1124 * Store a field to an object instance
1125 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001126 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001127static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001128 int fieldOffset)
1129{
1130 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001131 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
1132 RegLocation rlObj = getSrcLoc(cUnit, mir, 1);
1133 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1134 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1135 int regPtr;
1136 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1137 NULL);/* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -07001138#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001139 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
Jeff Hao97319a82009-08-12 16:57:15 -07001140#else
1141 /* Combine address and offset */
Bill Buzbee1465db52009-09-23 17:17:35 -07001142 regPtr = allocTemp(cUnit);
1143 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001144
Bill Buzbee1465db52009-09-23 17:17:35 -07001145 int regMap = rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001146 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
Jeff Hao97319a82009-08-12 16:57:15 -07001147#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001148}
1149
1150
Ben Chengba4fc8b2009-06-01 13:00:29 -07001151/*
1152 * Generate array load
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001154static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Bill Buzbee1465db52009-09-23 17:17:35 -07001155 RegLocation rlArray, RegLocation rlIndex,
1156 RegLocation rlDest, int scale)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001157{
1158 int lenOffset = offsetof(ArrayObject, length);
1159 int dataOffset = offsetof(ArrayObject, contents);
Bill Buzbee1465db52009-09-23 17:17:35 -07001160 RegLocation rlResult;
1161 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1162 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1163 int regPtr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001164
1165 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001166 ArmLIR * pcrLabel = NULL;
1167
1168 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001169 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
1170 rlArray.lowReg, mir->offset, NULL);
Ben Cheng4238ec22009-08-24 16:32:22 -07001171 }
1172
Bill Buzbee1465db52009-09-23 17:17:35 -07001173 regPtr = allocTemp(cUnit);
1174
Ben Cheng4238ec22009-08-24 16:32:22 -07001175 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001176 int regLen = allocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07001177 /* Get len */
Bill Buzbee1465db52009-09-23 17:17:35 -07001178 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1179 /* regPtr -> array data */
1180 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1181 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
1182 pcrLabel);
1183 freeTemp(cUnit, regLen);
Ben Cheng4238ec22009-08-24 16:32:22 -07001184 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001185 /* regPtr -> array data */
1186 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -07001187 }
Jeff Hao97319a82009-08-12 16:57:15 -07001188#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001189 if ((size == kLong) || (size == kDouble)) {
1190 if (scale) {
1191 int rNewIndex = allocTemp(cUnit);
1192 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1193 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1194 freeTemp(cUnit, rNewIndex);
1195 } else {
1196 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1197 }
1198 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1199 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1200 freeTemp(cUnit, regPtr);
1201 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001202 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001203 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1204 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1205 scale, size);
1206 freeTemp(cUnit, regPtr);
1207 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001208 }
Jeff Hao97319a82009-08-12 16:57:15 -07001209#else
Bill Buzbee270c1d62009-08-13 16:58:07 -07001210 //TODO: probably want to move this into loadBaseIndexed
1211 void *funct = NULL;
1212 switch(size) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001213 case kLong:
1214 case kDouble:
Jeff Hao97319a82009-08-12 16:57:15 -07001215 funct = (void*) &selfVerificationLoadDoubleword;
1216 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001217 case kWord:
Jeff Hao97319a82009-08-12 16:57:15 -07001218 funct = (void*) &selfVerificationLoad;
1219 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001220 case kUnsignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001221 funct = (void*) &selfVerificationLoadHalfword;
1222 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001223 case kSignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001224 funct = (void*) &selfVerificationLoadSignedHalfword;
1225 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001226 case kUnsignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001227 funct = (void*) &selfVerificationLoadByte;
1228 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001229 case kSignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001230 funct = (void*) &selfVerificationLoadSignedByte;
1231 break;
1232 default:
1233 assert(0);
1234 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -07001235 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001236 /* Combine address and index */
Bill Buzbee1465db52009-09-23 17:17:35 -07001237 if (scale) {
1238 int regTmp = allocTemp(cUnit);
1239 opRegRegImm(cUnit, kOpLsl, regTmp, rlIndex.lowReg, scale);
1240 opRegReg(cUnit, kOpAdd, regPtr, regTmp);
1241 freeTemp(cUnit, regTmp);
1242 } else {
1243 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1244 }
Jeff Hao97319a82009-08-12 16:57:15 -07001245
Bill Buzbee1465db52009-09-23 17:17:35 -07001246 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1247 int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001248 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1249
Bill Buzbee1465db52009-09-23 17:17:35 -07001250 freeTemp(cUnit, regPtr);
1251 if ((size == kLong) || (size == kDouble))
1252 storeValueWide(cUnit, rlDest, rlResult);
Jeff Hao97319a82009-08-12 16:57:15 -07001253 else
Bill Buzbee1465db52009-09-23 17:17:35 -07001254 storeValue(cUnit, rlDest, rlResult);
Jeff Hao97319a82009-08-12 16:57:15 -07001255#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001256}
1257
Ben Chengba4fc8b2009-06-01 13:00:29 -07001258/*
1259 * Generate array store
1260 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001261 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001262static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Bill Buzbee1465db52009-09-23 17:17:35 -07001263 RegLocation rlArray, RegLocation rlIndex,
1264 RegLocation rlSrc, int scale)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001265{
1266 int lenOffset = offsetof(ArrayObject, length);
1267 int dataOffset = offsetof(ArrayObject, contents);
1268
Bill Buzbee1465db52009-09-23 17:17:35 -07001269 int regPtr;
1270 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1271 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001272
Bill Buzbee1465db52009-09-23 17:17:35 -07001273 if (isTemp(cUnit, rlArray.lowReg)) {
1274 clobberReg(cUnit, rlArray.lowReg);
1275 regPtr = rlArray.lowReg;
1276 } else {
1277 regPtr = allocTemp(cUnit);
1278 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1279 }
Ben Chenge9695e52009-06-16 16:11:47 -07001280
Ben Cheng1efc9c52009-06-08 18:25:27 -07001281 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001282 ArmLIR * pcrLabel = NULL;
1283
1284 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001285 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
1286 mir->offset, NULL);
Ben Cheng4238ec22009-08-24 16:32:22 -07001287 }
1288
1289 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001290 int regLen = allocTemp(cUnit);
1291 //NOTE: max live temps(4) here.
Ben Cheng4238ec22009-08-24 16:32:22 -07001292 /* Get len */
Bill Buzbee1465db52009-09-23 17:17:35 -07001293 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1294 /* regPtr -> array data */
1295 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1296 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
1297 pcrLabel);
1298 freeTemp(cUnit, regLen);
Ben Cheng4238ec22009-08-24 16:32:22 -07001299 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001300 /* regPtr -> array data */
1301 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -07001302 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001303 /* at this point, regPtr points to array, 2 live temps */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001304#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001305 if ((size == kLong) || (size == kDouble)) {
1306 //TODO: need specific wide routine that can handle fp regs
1307 if (scale) {
1308 int rNewIndex = allocTemp(cUnit);
1309 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1310 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1311 freeTemp(cUnit, rNewIndex);
1312 } else {
1313 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1314 }
1315 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1316 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1317 freeTemp(cUnit, regPtr);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001318 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001319 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1320 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1321 scale, size);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001322 }
1323#else
1324 //TODO: probably want to move this into storeBaseIndexed
1325 void *funct = NULL;
1326 switch(size) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001327 case kLong:
1328 case kDouble:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001329 funct = (void*) &selfVerificationStoreDoubleword;
1330 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001331 case kWord:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001332 funct = (void*) &selfVerificationStore;
1333 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001334 case kSignedHalf:
1335 case kUnsignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001336 funct = (void*) &selfVerificationStoreHalfword;
1337 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001338 case kSignedByte:
1339 case kUnsignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001340 funct = (void*) &selfVerificationStoreByte;
1341 break;
1342 default:
1343 assert(0);
1344 dvmAbort();
1345 }
1346
Bill Buzbee1465db52009-09-23 17:17:35 -07001347 if (scale) {
1348 int regTmpIndex = allocTemp(cUnit);
1349 // 3 live temps
1350 opRegRegImm(cUnit, kOpLsl, regTmpIndex, rlIndex.lowReg, scale);
1351 opRegReg(cUnit, kOpAdd, regPtr, regTmpIndex);
1352 freeTemp(cUnit, regTmpIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001353 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001354 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001355 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001356 /* Combine address and index */
1357 if ((size == kLong) || (size == kDouble)) {
1358 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1359 } else {
1360 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1361 }
Jeff Hao97319a82009-08-12 16:57:15 -07001362
Bill Buzbee1465db52009-09-23 17:17:35 -07001363 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001364 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1365
Jeff Hao97319a82009-08-12 16:57:15 -07001366#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001367}
1368
Bill Buzbee1465db52009-09-23 17:17:35 -07001369static bool handleShiftOpLong(CompilationUnit *cUnit, MIR *mir,
1370 RegLocation rlDest, RegLocation rlSrc1,
1371 RegLocation rlShift)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001372{
Ben Chenge9695e52009-06-16 16:11:47 -07001373 /*
1374 * Don't mess with the regsiters here as there is a particular calling
1375 * convention to the out-of-line handler.
1376 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001377 RegLocation rlResult;
1378
1379 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1380 loadValueDirect(cUnit, rlShift, r2);
Ben Chenge9695e52009-06-16 16:11:47 -07001381 switch( mir->dalvikInsn.opCode) {
1382 case OP_SHL_LONG:
1383 case OP_SHL_LONG_2ADDR:
1384 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1385 break;
1386 case OP_SHR_LONG:
1387 case OP_SHR_LONG_2ADDR:
1388 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1389 break;
1390 case OP_USHR_LONG:
1391 case OP_USHR_LONG_2ADDR:
1392 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1393 break;
1394 default:
1395 return true;
1396 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001397 rlResult = getReturnLocWide(cUnit);
1398 storeValueWide(cUnit, rlDest, rlResult);
Ben Chenge9695e52009-06-16 16:11:47 -07001399 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001400}
Bill Buzbee1465db52009-09-23 17:17:35 -07001401bool handleArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1402 RegLocation rlDest, RegLocation rlSrc1,
1403 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001404{
Bill Buzbee1465db52009-09-23 17:17:35 -07001405 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001406 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001407
Ben Chengba4fc8b2009-06-01 13:00:29 -07001408 /* TODO: use a proper include file to define these */
1409 float __aeabi_fadd(float a, float b);
1410 float __aeabi_fsub(float a, float b);
1411 float __aeabi_fdiv(float a, float b);
1412 float __aeabi_fmul(float a, float b);
1413 float fmodf(float a, float b);
1414
1415 switch (mir->dalvikInsn.opCode) {
1416 case OP_ADD_FLOAT_2ADDR:
1417 case OP_ADD_FLOAT:
1418 funct = (void*) __aeabi_fadd;
1419 break;
1420 case OP_SUB_FLOAT_2ADDR:
1421 case OP_SUB_FLOAT:
1422 funct = (void*) __aeabi_fsub;
1423 break;
1424 case OP_DIV_FLOAT_2ADDR:
1425 case OP_DIV_FLOAT:
1426 funct = (void*) __aeabi_fdiv;
1427 break;
1428 case OP_MUL_FLOAT_2ADDR:
1429 case OP_MUL_FLOAT:
1430 funct = (void*) __aeabi_fmul;
1431 break;
1432 case OP_REM_FLOAT_2ADDR:
1433 case OP_REM_FLOAT:
1434 funct = (void*) fmodf;
1435 break;
1436 case OP_NEG_FLOAT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001437 genNegFloat(cUnit, rlDest, rlSrc1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001438 return false;
1439 }
1440 default:
1441 return true;
1442 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001443 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001444 loadValueDirectFixed(cUnit, rlSrc1, r0);
1445 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001446 loadConstant(cUnit, r2, (int)funct);
Bill Buzbee1465db52009-09-23 17:17:35 -07001447 opReg(cUnit, kOpBlx, r2);
1448 clobberCallRegs(cUnit);
1449 rlResult = getReturnLoc(cUnit);
1450 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001451 return false;
1452}
1453
Bill Buzbee1465db52009-09-23 17:17:35 -07001454bool handleArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1455 RegLocation rlDest, RegLocation rlSrc1,
1456 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001457{
Bill Buzbee1465db52009-09-23 17:17:35 -07001458 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001459 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001460
Ben Chengba4fc8b2009-06-01 13:00:29 -07001461 /* TODO: use a proper include file to define these */
1462 double __aeabi_dadd(double a, double b);
1463 double __aeabi_dsub(double a, double b);
1464 double __aeabi_ddiv(double a, double b);
1465 double __aeabi_dmul(double a, double b);
1466 double fmod(double a, double b);
1467
1468 switch (mir->dalvikInsn.opCode) {
1469 case OP_ADD_DOUBLE_2ADDR:
1470 case OP_ADD_DOUBLE:
1471 funct = (void*) __aeabi_dadd;
1472 break;
1473 case OP_SUB_DOUBLE_2ADDR:
1474 case OP_SUB_DOUBLE:
1475 funct = (void*) __aeabi_dsub;
1476 break;
1477 case OP_DIV_DOUBLE_2ADDR:
1478 case OP_DIV_DOUBLE:
1479 funct = (void*) __aeabi_ddiv;
1480 break;
1481 case OP_MUL_DOUBLE_2ADDR:
1482 case OP_MUL_DOUBLE:
1483 funct = (void*) __aeabi_dmul;
1484 break;
1485 case OP_REM_DOUBLE_2ADDR:
1486 case OP_REM_DOUBLE:
1487 funct = (void*) fmod;
1488 break;
1489 case OP_NEG_DOUBLE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001490 genNegDouble(cUnit, rlDest, rlSrc1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001491 return false;
1492 }
1493 default:
1494 return true;
1495 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001496 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001497 loadConstant(cUnit, rlr, (int)funct);
1498 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1499 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1500 opReg(cUnit, kOpBlx, rlr);
1501 clobberCallRegs(cUnit);
1502 rlResult = getReturnLocWide(cUnit);
1503 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001504 return false;
1505}
1506
Bill Buzbee1465db52009-09-23 17:17:35 -07001507static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir,
1508 RegLocation rlDest, RegLocation rlSrc1,
1509 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001510{
Bill Buzbee1465db52009-09-23 17:17:35 -07001511 RegLocation rlResult;
1512 OpKind firstOp = kOpBkpt;
1513 OpKind secondOp = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001514 bool callOut = false;
1515 void *callTgt;
1516 int retReg = r0;
1517 /* TODO - find proper .h file to declare these */
1518 long long __aeabi_ldivmod(long long op1, long long op2);
1519
1520 switch (mir->dalvikInsn.opCode) {
1521 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07001522 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1523 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1524 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1525 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1526 storeValueWide(cUnit, rlDest, rlResult);
1527 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001528 break;
1529 case OP_ADD_LONG:
1530 case OP_ADD_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001531 firstOp = kOpAdd;
1532 secondOp = kOpAdc;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001533 break;
1534 case OP_SUB_LONG:
1535 case OP_SUB_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001536 firstOp = kOpSub;
1537 secondOp = kOpSbc;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001538 break;
1539 case OP_MUL_LONG:
1540 case OP_MUL_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001541 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001542 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001543 case OP_DIV_LONG:
1544 case OP_DIV_LONG_2ADDR:
1545 callOut = true;
1546 retReg = r0;
1547 callTgt = (void*)__aeabi_ldivmod;
1548 break;
1549 /* NOTE - result is in r2/r3 instead of r0/r1 */
1550 case OP_REM_LONG:
1551 case OP_REM_LONG_2ADDR:
1552 callOut = true;
1553 callTgt = (void*)__aeabi_ldivmod;
1554 retReg = r2;
1555 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001556 case OP_AND_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001557 case OP_AND_LONG:
1558 firstOp = kOpAnd;
1559 secondOp = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001560 break;
1561 case OP_OR_LONG:
1562 case OP_OR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001563 firstOp = kOpOr;
1564 secondOp = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001565 break;
1566 case OP_XOR_LONG:
1567 case OP_XOR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001568 firstOp = kOpXor;
1569 secondOp = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001570 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001571 case OP_NEG_LONG: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001572 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1573 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1574 loadConstantValue(cUnit, rlResult.highReg, 0);
1575 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1576 rlResult.highReg, rlSrc2.lowReg);
1577 opRegReg(cUnit, kOpSbc, rlResult.highReg, rlSrc2.highReg);
1578 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001579 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001580 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001581 default:
1582 LOGE("Invalid long arith op");
1583 dvmAbort();
1584 }
1585 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001586 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001587 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001588 // Adjust return regs in to handle case of rem returning r2/r3
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001589 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001590 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1591 loadConstant(cUnit, rlr, (int) callTgt);
1592 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1593 opReg(cUnit, kOpBlx, rlr);
1594 clobberCallRegs(cUnit);
1595 if (retReg == r0)
1596 rlResult = getReturnLocWide(cUnit);
1597 else
1598 rlResult = getReturnLocWideAlt(cUnit);
1599 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001600 }
1601 return false;
1602}
1603
Bill Buzbee1465db52009-09-23 17:17:35 -07001604static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir,
1605 RegLocation rlDest, RegLocation rlSrc1,
1606 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001607{
Bill Buzbee1465db52009-09-23 17:17:35 -07001608 OpKind op = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001609 bool callOut = false;
1610 bool checkZero = false;
Bill Buzbee1465db52009-09-23 17:17:35 -07001611 bool unary = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001612 int retReg = r0;
1613 void *callTgt;
Bill Buzbee1465db52009-09-23 17:17:35 -07001614 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001615
1616 /* TODO - find proper .h file to declare these */
1617 int __aeabi_idivmod(int op1, int op2);
1618 int __aeabi_idiv(int op1, int op2);
1619
1620 switch (mir->dalvikInsn.opCode) {
1621 case OP_NEG_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001622 op = kOpNeg;
1623 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001624 break;
1625 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001626 op = kOpMvn;
1627 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001628 break;
1629 case OP_ADD_INT:
1630 case OP_ADD_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001631 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001632 break;
1633 case OP_SUB_INT:
1634 case OP_SUB_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001635 op = kOpSub;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001636 break;
1637 case OP_MUL_INT:
1638 case OP_MUL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001639 op = kOpMul;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001640 break;
1641 case OP_DIV_INT:
1642 case OP_DIV_INT_2ADDR:
1643 callOut = true;
1644 checkZero = true;
1645 callTgt = __aeabi_idiv;
1646 retReg = r0;
1647 break;
1648 /* NOTE: returns in r1 */
1649 case OP_REM_INT:
1650 case OP_REM_INT_2ADDR:
1651 callOut = true;
1652 checkZero = true;
1653 callTgt = __aeabi_idivmod;
1654 retReg = r1;
1655 break;
1656 case OP_AND_INT:
1657 case OP_AND_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001658 op = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001659 break;
1660 case OP_OR_INT:
1661 case OP_OR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001662 op = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001663 break;
1664 case OP_XOR_INT:
1665 case OP_XOR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001666 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001667 break;
1668 case OP_SHL_INT:
1669 case OP_SHL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001670 op = kOpLsl;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001671 break;
1672 case OP_SHR_INT:
1673 case OP_SHR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001674 op = kOpAsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001675 break;
1676 case OP_USHR_INT:
1677 case OP_USHR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001678 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001679 break;
1680 default:
1681 LOGE("Invalid word arith op: 0x%x(%d)",
1682 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1683 dvmAbort();
1684 }
1685 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001686 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1687 if (unary) {
1688 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1689 opRegReg(cUnit, op, rlResult.lowReg,
1690 rlSrc1.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001691 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001692 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1693 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1694 opRegRegReg(cUnit, op, rlResult.lowReg,
1695 rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001696 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001697 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001698 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001699 RegLocation rlResult;
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001700 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001701 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001702 loadConstant(cUnit, r2, (int) callTgt);
Bill Buzbee1465db52009-09-23 17:17:35 -07001703 loadValueDirectFixed(cUnit, rlSrc1, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001704 if (checkZero) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001705 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001706 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001707 opReg(cUnit, kOpBlx, r2);
1708 clobberCallRegs(cUnit);
1709 if (retReg == r0)
1710 rlResult = getReturnLoc(cUnit);
1711 else
1712 rlResult = getReturnLocAlt(cUnit);
1713 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001714 }
1715 return false;
1716}
1717
Bill Buzbee1465db52009-09-23 17:17:35 -07001718static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001719{
1720 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001721 RegLocation rlDest;
1722 RegLocation rlSrc1;
1723 RegLocation rlSrc2;
1724 /* Deduce sizes of operands */
1725 if (mir->ssaRep->numUses == 2) {
1726 rlSrc1 = getSrcLoc(cUnit, mir, 0);
1727 rlSrc2 = getSrcLoc(cUnit, mir, 1);
1728 } else if (mir->ssaRep->numUses == 3) {
1729 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1730 rlSrc2 = getSrcLoc(cUnit, mir, 2);
1731 } else {
1732 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1733 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
1734 assert(mir->ssaRep->numUses == 4);
1735 }
1736 if (mir->ssaRep->numDefs == 1) {
1737 rlDest = getDestLoc(cUnit, mir, 0);
1738 } else {
1739 assert(mir->ssaRep->numDefs == 2);
1740 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1741 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001742
1743 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001744 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001745 }
1746 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001747 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001748 }
1749 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001750 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001751 }
1752 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001753 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001754 }
1755 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001756 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001757 }
1758 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001759 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001760 }
1761 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001762 return handleArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001763 }
1764 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001765 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001766 }
1767 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001768 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001769 }
1770 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001771 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001772 }
1773 return true;
1774}
1775
Bill Buzbee1465db52009-09-23 17:17:35 -07001776/* Generate conditional branch instructions */
1777static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1778 ArmConditionCode cond,
1779 ArmLIR *target)
1780{
1781 ArmLIR *branch = opCondBranch(cUnit, cond);
1782 branch->generic.target = (LIR *) target;
1783 return branch;
1784}
1785
1786/* Generate unconditional branch instructions */
1787static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1788{
1789 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
1790 branch->generic.target = (LIR *) target;
1791 return branch;
1792}
1793
1794/*
1795 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
1796 * blocks.
1797 */
1798static void genBarrier(CompilationUnit *cUnit)
1799{
1800 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
1801 /* Mark all resources as being clobbered */
1802 barrier->defMask = -1;
1803}
1804
1805/* Perform the actual operation for OP_RETURN_* */
1806static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
1807{
1808 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
1809#if defined(INVOKE_STATS)
1810 gDvmJit.returnOp++;
1811#endif
1812 int dPC = (int) (cUnit->method->insns + mir->offset);
1813 /* Insert branch, but defer setting of target */
1814 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
1815 /* Set up the place holder to reconstruct this Dalvik PC */
1816 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1817 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
1818 pcrLabel->operands[0] = dPC;
1819 pcrLabel->operands[1] = mir->offset;
1820 /* Insert the place holder to the growable list */
1821 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1822 /* Branch to the PC reconstruction code */
1823 branch->generic.target = (LIR *) pcrLabel;
1824}
1825
Bill Buzbeed45ba372009-06-15 17:00:57 -07001826static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1827 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001828{
Ben Chenge9695e52009-06-16 16:11:47 -07001829 /*
1830 * Don't optimize the register usage since it calls out to template
1831 * functions
1832 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001833 RegLocation rlSrc;
1834 RegLocation rlDest;
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001835 flushAllRegs(cUnit); /* Send everything to home location */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001836 if (srcSize == 1) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001837 rlSrc = getSrcLoc(cUnit, mir, 0);
1838 loadValueDirectFixed(cUnit, rlSrc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001839 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001840 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1841 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001842 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001843 loadConstant(cUnit, r2, (int)funct);
1844 opReg(cUnit, kOpBlx, r2);
1845 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001846 if (tgtSize == 1) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001847 RegLocation rlResult;
1848 rlDest = getDestLoc(cUnit, mir, 0);
1849 rlResult = getReturnLoc(cUnit);
1850 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001851 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001852 RegLocation rlResult;
1853 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1854 rlResult = getReturnLocWide(cUnit);
1855 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001856 }
1857 return false;
1858}
1859
Ben Chengba4fc8b2009-06-01 13:00:29 -07001860static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1861 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001862 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001863{
1864 unsigned int i;
1865 unsigned int regMask = 0;
Bill Buzbee1465db52009-09-23 17:17:35 -07001866 RegLocation rlArg;
1867 int numDone = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001868
Bill Buzbee1465db52009-09-23 17:17:35 -07001869 /*
1870 * Load arguments to r0..r4. Note that these registers may contain
1871 * live values, so we clobber them immediately after loading to prevent
1872 * them from being used as sources for subsequent loads.
1873 */
1874 lockAllTemps(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001875 for (i = 0; i < dInsn->vA; i++) {
1876 regMask |= 1 << i;
Bill Buzbee1465db52009-09-23 17:17:35 -07001877 rlArg = getSrcLoc(cUnit, mir, numDone++);
1878 loadValueDirectFixed(cUnit, rlArg, i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001879 }
1880 if (regMask) {
1881 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee1465db52009-09-23 17:17:35 -07001882 opRegRegImm(cUnit, kOpSub, r7, rFP,
1883 sizeof(StackSaveArea) + (dInsn->vA << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001884 /* generate null check */
1885 if (pcrLabel) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001886 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1887 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001888 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001889 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001890 }
1891}
1892
1893static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1894 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001895 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001896{
1897 int srcOffset = dInsn->vC << 2;
1898 int numArgs = dInsn->vA;
1899 int regMask;
Bill Buzbee1465db52009-09-23 17:17:35 -07001900
1901 /*
1902 * Note: here, all promoted registers will have been flushed
1903 * back to the Dalvik base locations, so register usage restrictins
1904 * are lifted. All parms loaded from original Dalvik register
1905 * region - even though some might conceivably have valid copies
1906 * cached in a preserved register.
1907 */
1908 lockAllTemps(cUnit);
1909
Ben Chengba4fc8b2009-06-01 13:00:29 -07001910 /*
1911 * r4PC : &rFP[vC]
1912 * r7: &newFP[0]
1913 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001914 opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001915 /* load [r0 .. min(numArgs,4)] */
1916 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001917 /*
1918 * Protect the loadMultiple instruction from being reordered with other
1919 * Dalvik stack accesses.
1920 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001921 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001922
Bill Buzbee1465db52009-09-23 17:17:35 -07001923 opRegRegImm(cUnit, kOpSub, r7, rFP,
1924 sizeof(StackSaveArea) + (numArgs << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001925 /* generate null check */
1926 if (pcrLabel) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001927 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1928 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001929 }
1930
1931 /*
1932 * Handle remaining 4n arguments:
1933 * store previously loaded 4 values and load the next 4 values
1934 */
1935 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001936 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001937 /*
1938 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001939 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001940 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001941 opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001942 /* No need to generate the loop structure if numArgs <= 11 */
1943 if (numArgs > 11) {
1944 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee1465db52009-09-23 17:17:35 -07001945 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07001946 loopLabel->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001947 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001948 storeMultiple(cUnit, r7, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001949 /*
1950 * Protect the loadMultiple instruction from being reordered with other
1951 * Dalvik stack accesses.
1952 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001953 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001954 /* No need to generate the loop structure if numArgs <= 11 */
1955 if (numArgs > 11) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001956 opRegImm(cUnit, kOpSub, rFP, 4);
1957 genConditionalBranch(cUnit, kArmCondNe, loopLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001958 }
1959 }
1960
1961 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001962 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001963
1964 /* Generate the loop epilogue - don't use r0 */
1965 if ((numArgs > 4) && (numArgs % 4)) {
1966 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001967 /*
1968 * Protect the loadMultiple instruction from being reordered with other
1969 * Dalvik stack accesses.
1970 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001971 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001972 }
1973 if (numArgs >= 8)
Bill Buzbee1465db52009-09-23 17:17:35 -07001974 opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001975
1976 /* Save the modulo 4 arguments */
1977 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001978 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001979 }
1980}
1981
Ben Cheng38329f52009-07-07 14:19:20 -07001982/*
1983 * Generate code to setup the call stack then jump to the chaining cell if it
1984 * is not a native method.
1985 */
1986static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001987 BasicBlock *bb, ArmLIR *labelList,
1988 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001989 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001990{
Bill Buzbee1465db52009-09-23 17:17:35 -07001991 /*
1992 * Note: all Dalvik register state should be flushed to
1993 * memory by the point, so register usage restrictions no
1994 * longer apply. All temp & preserved registers may be used.
1995 */
1996 lockAllTemps(cUnit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001997 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001998
1999 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002000 lockTemp(cUnit, r1);
2001 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002002 /* r4PC = dalvikCallsite */
2003 loadConstant(cUnit, r4PC,
2004 (int) (cUnit->method->insns + mir->offset));
2005 addrRetChain->generic.target = (LIR *) retChainingCell;
2006 /*
Ben Cheng38329f52009-07-07 14:19:20 -07002007 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002008 * r1 = &ChainingCell
2009 * r4PC = callsiteDPC
2010 */
2011 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07002012 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002013#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07002014 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002015#endif
2016 } else {
2017 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
2018#if defined(INVOKE_STATS)
2019 gDvmJit.invokeChain++;
2020#endif
Ben Cheng38329f52009-07-07 14:19:20 -07002021 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002022 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2023 }
2024 /* Handle exceptions using the interpreter */
2025 genTrap(cUnit, mir->offset, pcrLabel);
2026}
2027
Ben Cheng38329f52009-07-07 14:19:20 -07002028/*
2029 * Generate code to check the validity of a predicted chain and take actions
2030 * based on the result.
2031 *
2032 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
2033 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
2034 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
2035 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
2036 * 0x426a99b2 : blx_2 see above --+
2037 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
2038 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
2039 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
2040 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
2041 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
2042 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
2043 * 0x426a99c0 : blx r7 --+
2044 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
2045 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2046 * 0x426a99c6 : blx_2 see above --+
2047 */
2048static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
2049 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002050 ArmLIR *retChainingCell,
2051 ArmLIR *predChainingCell,
2052 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07002053{
Bill Buzbee1465db52009-09-23 17:17:35 -07002054 /*
2055 * Note: all Dalvik register state should be flushed to
2056 * memory by the point, so register usage restrictions no
2057 * longer apply. Lock temps to prevent them from being
2058 * allocated by utility routines.
2059 */
2060 lockAllTemps(cUnit);
2061
Ben Cheng38329f52009-07-07 14:19:20 -07002062 /* "this" is already left in r0 by genProcessArgs* */
2063
2064 /* r4PC = dalvikCallsite */
2065 loadConstant(cUnit, r4PC,
2066 (int) (cUnit->method->insns + mir->offset));
2067
2068 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002069 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002070 addrRetChain->generic.target = (LIR *) retChainingCell;
2071
2072 /* r2 = &predictedChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002073 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002074 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2075
2076 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2077
2078 /* return through lr - jump to the chaining cell */
2079 genUnconditionalBranch(cUnit, predChainingCell);
2080
2081 /*
2082 * null-check on "this" may have been eliminated, but we still need a PC-
2083 * reconstruction label for stack overflow bailout.
2084 */
2085 if (pcrLabel == NULL) {
2086 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002087 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07002088 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07002089 pcrLabel->operands[0] = dPC;
2090 pcrLabel->operands[1] = mir->offset;
2091 /* Insert the place holder to the growable list */
2092 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2093 }
2094
2095 /* return through lr+2 - punt to the interpreter */
2096 genUnconditionalBranch(cUnit, pcrLabel);
2097
2098 /*
2099 * return through lr+4 - fully resolve the callee method.
2100 * r1 <- count
2101 * r2 <- &predictedChainCell
2102 * r3 <- this->class
2103 * r4 <- dPC
2104 * r7 <- this->class->vtable
2105 */
2106
2107 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002108 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07002109
2110 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07002111 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002112
Bill Buzbee1465db52009-09-23 17:17:35 -07002113 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07002114
Bill Buzbee270c1d62009-08-13 16:58:07 -07002115 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2116 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002117
2118 /*
2119 * r0 = calleeMethod
2120 * r2 = &predictedChainingCell
2121 * r3 = class
2122 *
2123 * &returnChainingCell has been loaded into r1 but is not needed
2124 * when patching the chaining cell and will be clobbered upon
2125 * returning so it will be reconstructed again.
2126 */
Bill Buzbee1465db52009-09-23 17:17:35 -07002127 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002128
2129 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002130 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002131 addrRetChain->generic.target = (LIR *) retChainingCell;
2132
2133 bypassRechaining->generic.target = (LIR *) addrRetChain;
2134 /*
2135 * r0 = calleeMethod,
2136 * r1 = &ChainingCell,
2137 * r4PC = callsiteDPC,
2138 */
2139 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2140#if defined(INVOKE_STATS)
2141 gDvmJit.invokePredictedChain++;
2142#endif
2143 /* Handle exceptions using the interpreter */
2144 genTrap(cUnit, mir->offset, pcrLabel);
2145}
2146
2147/*
2148 * Up calling this function, "this" is stored in r0. The actual class will be
2149 * chased down off r0 and the predicted one will be retrieved through
2150 * predictedChainingCell then a comparison is performed to see whether the
2151 * previously established chaining is still valid.
2152 *
2153 * The return LIR is a branch based on the comparison result. The actual branch
2154 * target will be setup in the caller.
2155 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002156static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
2157 ArmLIR *predChainingCell,
2158 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07002159 MIR *mir)
2160{
Bill Buzbee1465db52009-09-23 17:17:35 -07002161 /*
2162 * Note: all Dalvik register state should be flushed to
2163 * memory by the point, so register usage restrictions no
2164 * longer apply. All temp & preserved registers may be used.
2165 */
2166 lockAllTemps(cUnit);
2167
Ben Cheng38329f52009-07-07 14:19:20 -07002168 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002169 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002170
2171 /*
2172 * r2 now contains predicted class. The starting offset of the
2173 * cached value is 4 bytes into the chaining cell.
2174 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002175 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002176 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07002177 getPredictedClass->generic.target = (LIR *) predChainingCell;
2178
2179 /*
2180 * r0 now contains predicted method. The starting offset of the
2181 * cached value is 8 bytes into the chaining cell.
2182 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002183 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002184 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07002185 getPredictedMethod->generic.target = (LIR *) predChainingCell;
2186
2187 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002188 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002189 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002190 getRechainingRequestCount->generic.target =
2191 (LIR *) predChainingCell;
2192
2193 /* r4PC = dalvikCallsite */
2194 loadConstant(cUnit, r4PC,
2195 (int) (cUnit->method->insns + mir->offset));
2196
2197 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002198 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002199 addrRetChain->generic.target = (LIR *) retChainingCell;
2200
2201 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee1465db52009-09-23 17:17:35 -07002202 opRegReg(cUnit, kOpCmp, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002203
Bill Buzbee1465db52009-09-23 17:17:35 -07002204 return opCondBranch(cUnit, kArmCondEq);
Ben Cheng38329f52009-07-07 14:19:20 -07002205}
2206
Ben Chengba4fc8b2009-06-01 13:00:29 -07002207/* Geneate a branch to go back to the interpreter */
2208static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
2209{
2210 /* r0 = dalvik pc */
Bill Buzbee1465db52009-09-23 17:17:35 -07002211 flushAllRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002212 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002213 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
2214 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2215 jitToInterpEntries.dvmJitToInterpPunt), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002216 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002217}
2218
2219/*
2220 * Attempt to single step one instruction using the interpreter and return
2221 * to the compiled code for the next Dalvik instruction
2222 */
2223static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
2224{
2225 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
2226 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
2227 kInstrCanThrow;
Bill Buzbee1465db52009-09-23 17:17:35 -07002228
2229 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
2230 flushAllRegs(cUnit);
2231
Ben Chengba4fc8b2009-06-01 13:00:29 -07002232 if ((mir->next == NULL) || (flags & flagsToCheck)) {
2233 genPuntToInterp(cUnit, mir->offset);
2234 return;
2235 }
2236 int entryAddr = offsetof(InterpState,
2237 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002238 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002239 /* r0 = dalvik pc */
2240 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
2241 /* r1 = dalvik pc of following instruction */
2242 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -07002243 opReg(cUnit, kOpBlx, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002244}
2245
Bill Buzbee1465db52009-09-23 17:17:35 -07002246static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002247{
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002248 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002249 genExportPC(cUnit, mir);
2250 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2251 loadValueDirectFixed(cUnit, rlSrc, r1);
2252 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
2253 if (mir->dalvikInsn.opCode == OP_MONITOR_ENTER) {
2254 loadConstant(cUnit, r2, (int)dvmLockObject);
2255 } else {
2256 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2257 }
2258 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
2259 /* Do the call */
2260 opReg(cUnit, kOpBlx, r2);
2261 clobberCallRegs(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002262}
2263
2264/* Load a word at base + displacement. Displacement must be word multiple */
2265static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
2266 int rDest)
2267{
Bill Buzbee1465db52009-09-23 17:17:35 -07002268 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, false,
2269 INVALID_SREG);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002270}
2271
2272static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
Bill Buzbee1465db52009-09-23 17:17:35 -07002273 int displacement, int rSrc)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002274{
Bill Buzbee1465db52009-09-23 17:17:35 -07002275 return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002276}
2277
2278static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
2279{
2280 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
2281 dvmCompilerAppendLIR(cUnit, (LIR*)res);
2282 return res;
2283}
2284
Ben Chengba4fc8b2009-06-01 13:00:29 -07002285/*
2286 * The following are the first-level codegen routines that analyze the format
2287 * of each bytecode then either dispatch special purpose codegen routines
2288 * or produce corresponding Thumb instructions directly.
2289 */
2290
2291static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002292 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002293{
2294 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2295 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2296 return false;
2297}
2298
2299static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
2300{
2301 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2302 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
2303 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
2304 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2305 return true;
2306 }
2307 switch (dalvikOpCode) {
2308 case OP_RETURN_VOID:
2309 genReturnCommon(cUnit,mir);
2310 break;
2311 case OP_UNUSED_73:
2312 case OP_UNUSED_79:
2313 case OP_UNUSED_7A:
2314 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2315 return true;
2316 case OP_NOP:
2317 break;
2318 default:
2319 return true;
2320 }
2321 return false;
2322}
2323
2324static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2325{
Bill Buzbee1465db52009-09-23 17:17:35 -07002326 RegLocation rlDest;
2327 RegLocation rlResult;
2328 if (mir->ssaRep->numDefs == 2) {
2329 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2330 } else {
2331 rlDest = getDestLoc(cUnit, mir, 0);
2332 }
Ben Chenge9695e52009-06-16 16:11:47 -07002333
Ben Chengba4fc8b2009-06-01 13:00:29 -07002334 switch (mir->dalvikInsn.opCode) {
2335 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07002336 case OP_CONST_4: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002337 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2338 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2339 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002340 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002341 }
2342 case OP_CONST_WIDE_32: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002343 //TUNING: single routine to load constant pair for support doubles
2344 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2345 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2346 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2347 rlResult.lowReg, 31);
2348 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002349 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002350 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002351 default:
2352 return true;
2353 }
2354 return false;
2355}
2356
2357static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2358{
Bill Buzbee1465db52009-09-23 17:17:35 -07002359 RegLocation rlDest;
2360 RegLocation rlResult;
2361 if (mir->ssaRep->numDefs == 2) {
2362 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2363 } else {
2364 rlDest = getDestLoc(cUnit, mir, 0);
2365 }
2366 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Ben Chenge9695e52009-06-16 16:11:47 -07002367
Ben Chengba4fc8b2009-06-01 13:00:29 -07002368 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07002369 case OP_CONST_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002370 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
2371 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002372 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002373 }
2374 case OP_CONST_WIDE_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002375 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
2376 0, mir->dalvikInsn.vB << 16);
2377 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002378 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002379 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002380 default:
2381 return true;
2382 }
2383 return false;
2384}
2385
2386static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2387{
2388 /* For OP_THROW_VERIFICATION_ERROR */
2389 genInterpSingleStep(cUnit, mir);
2390 return false;
2391}
2392
2393static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2394{
Bill Buzbee1465db52009-09-23 17:17:35 -07002395 RegLocation rlResult;
2396 RegLocation rlDest;
2397 RegLocation rlSrc;
Ben Chenge9695e52009-06-16 16:11:47 -07002398
Ben Chengba4fc8b2009-06-01 13:00:29 -07002399 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002400 case OP_CONST_STRING_JUMBO:
2401 case OP_CONST_STRING: {
2402 void *strPtr = (void*)
2403 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2404 assert(strPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002405 rlDest = getDestLoc(cUnit, mir, 0);
2406 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2407 loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
2408 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002409 break;
2410 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002411 case OP_CONST_CLASS: {
2412 void *classPtr = (void*)
2413 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2414 assert(classPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002415 rlDest = getDestLoc(cUnit, mir, 0);
2416 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2417 loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
2418 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002419 break;
2420 }
2421 case OP_SGET_OBJECT:
2422 case OP_SGET_BOOLEAN:
2423 case OP_SGET_CHAR:
2424 case OP_SGET_BYTE:
2425 case OP_SGET_SHORT:
2426 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002427 int valOffset = offsetof(StaticField, value);
Bill Buzbee1465db52009-09-23 17:17:35 -07002428 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002429 void *fieldPtr = (void*)
2430 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2431 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002432 rlDest = getDestLoc(cUnit, mir, 0);
2433 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2434 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002435#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002436 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002437#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002438 int regMap = rlResult.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002439 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2440
Jeff Hao97319a82009-08-12 16:57:15 -07002441#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002442 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002443 break;
2444 }
2445 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002446 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002447 void *fieldPtr = (void*)
2448 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Bill Buzbee1465db52009-09-23 17:17:35 -07002449 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002450 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002451 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2452 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2453 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002454#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002455 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002456#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002457 int regMap = rlResult.highReg << 16 |
2458 rlResult.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002459 selfVerificationMemOpWrapper(cUnit, regMap,
2460 &selfVerificationLoadDoubleword);
2461
Jeff Hao97319a82009-08-12 16:57:15 -07002462#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002463 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002464 break;
2465 }
2466 case OP_SPUT_OBJECT:
2467 case OP_SPUT_BOOLEAN:
2468 case OP_SPUT_CHAR:
2469 case OP_SPUT_BYTE:
2470 case OP_SPUT_SHORT:
2471 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002472 int valOffset = offsetof(StaticField, value);
Bill Buzbee1465db52009-09-23 17:17:35 -07002473 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002474 void *fieldPtr = (void*)
2475 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002476
Ben Chengba4fc8b2009-06-01 13:00:29 -07002477 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002478 rlSrc = getSrcLoc(cUnit, mir, 0);
2479 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
2480 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002481#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002482 storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002483#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002484 int regMap = rlSrc.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002485 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2486#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002487 break;
2488 }
2489 case OP_SPUT_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002490 int tReg = allocTemp(cUnit);
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002491 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002492 void *fieldPtr = (void*)
2493 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002494
Ben Chengba4fc8b2009-06-01 13:00:29 -07002495 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002496 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2497 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
2498 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002499#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002500 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002501#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002502 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002503 selfVerificationMemOpWrapper(cUnit, regMap,
2504 &selfVerificationStoreDoubleword);
2505#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002506 break;
2507 }
2508 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002509 /*
2510 * Obey the calling convention and don't mess with the register
2511 * usage.
2512 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002513 ClassObject *classPtr = (void*)
2514 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2515 assert(classPtr != NULL);
2516 assert(classPtr->status & CLASS_INITIALIZED);
Ben Cheng79d173c2009-09-29 16:12:51 -07002517 /*
2518 * If it is going to throw, it should not make to the trace to begin
Bill Buzbee1465db52009-09-23 17:17:35 -07002519 * with. However, Alloc might throw, so we need to genExportPC()
Ben Cheng79d173c2009-09-29 16:12:51 -07002520 */
2521 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002522 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002523 genExportPC(cUnit, mir);
2524 loadConstant(cUnit, r2, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002525 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002526 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07002527 opReg(cUnit, kOpBlx, r2);
2528 clobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07002529 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07002530 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2531 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07002532 /*
2533 * OOM exception needs to be thrown here and cannot re-execute
2534 */
2535 loadConstant(cUnit, r0,
2536 (int) (cUnit->method->insns + mir->offset));
2537 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2538 /* noreturn */
2539
Bill Buzbee1465db52009-09-23 17:17:35 -07002540 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07002541 target->defMask = ENCODE_ALL;
2542 branchOver->generic.target = (LIR *) target;
Bill Buzbee1465db52009-09-23 17:17:35 -07002543 rlDest = getDestLoc(cUnit, mir, 0);
2544 rlResult = getReturnLoc(cUnit);
2545 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002546 break;
2547 }
2548 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002549 /*
2550 * Obey the calling convention and don't mess with the register
2551 * usage.
2552 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002553 ClassObject *classPtr =
2554 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002555 flushAllRegs(cUnit); /* Send everything to home location */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002556 loadConstant(cUnit, r1, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07002557 rlSrc = getSrcLoc(cUnit, mir, 0);
2558 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2559 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); /* Null? */
2560 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
2561 /*
2562 * rlSrc.lowReg now contains object->clazz. Note that
2563 * it could have been allocated r0, but we're okay so long
2564 * as we don't do anything desctructive until r0 is loaded
2565 * with clazz.
2566 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002567 /* r0 now contains object->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07002568 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
2569 loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
2570 opRegReg(cUnit, kOpCmp, r0, r1);
2571 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2572 opReg(cUnit, kOpBlx, r2);
2573 clobberCallRegs(cUnit);
2574 /*
2575 * If null, check cast failed - punt to the interpreter. Because
2576 * interpreter will be the one throwing, we don't need to
2577 * genExportPC() here.
2578 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002579 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002580 /* check cast passed - branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07002581 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07002582 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002583 branch1->generic.target = (LIR *)target;
2584 branch2->generic.target = (LIR *)target;
2585 break;
2586 }
2587 default:
2588 return true;
2589 }
2590 return false;
2591}
2592
2593static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2594{
2595 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002596 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002597 switch (dalvikOpCode) {
2598 case OP_MOVE_EXCEPTION: {
2599 int offset = offsetof(InterpState, self);
2600 int exOffset = offsetof(Thread, exception);
Bill Buzbee1465db52009-09-23 17:17:35 -07002601 int selfReg = allocTemp(cUnit);
2602 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2603 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2604 loadWordDisp(cUnit, rGLUE, offset, selfReg);
2605 loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
2606 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002607 break;
2608 }
2609 case OP_MOVE_RESULT:
2610 case OP_MOVE_RESULT_OBJECT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002611 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2612 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
2613 rlSrc.fp = rlDest.fp;
2614 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002615 break;
2616 }
2617 case OP_MOVE_RESULT_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002618 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
2619 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
2620 rlSrc.fp = rlDest.fp;
2621 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002622 break;
2623 }
2624 case OP_RETURN_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002625 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2626 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
2627 rlDest.fp = rlSrc.fp;
2628 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002629 genReturnCommon(cUnit,mir);
2630 break;
2631 }
2632 case OP_RETURN:
2633 case OP_RETURN_OBJECT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002634 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2635 RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
2636 rlDest.fp = rlSrc.fp;
2637 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002638 genReturnCommon(cUnit,mir);
2639 break;
2640 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002641 case OP_MONITOR_EXIT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002642 case OP_MONITOR_ENTER:
Bill Buzbee1465db52009-09-23 17:17:35 -07002643#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
2644 handleMonitorPortable(cUnit, mir);
2645#else
2646 handleMonitor(cUnit, mir);
2647#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002648 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002649 case OP_THROW: {
2650 genInterpSingleStep(cUnit, mir);
2651 break;
2652 }
2653 default:
2654 return true;
2655 }
2656 return false;
2657}
2658
Bill Buzbee1465db52009-09-23 17:17:35 -07002659static bool handleConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002660{
2661 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002662
Ben Chengba4fc8b2009-06-01 13:00:29 -07002663 float __aeabi_i2f( int op1 );
2664 int __aeabi_f2iz( float op1 );
2665 float __aeabi_d2f( double op1 );
2666 double __aeabi_f2d( float op1 );
2667 double __aeabi_i2d( int op1 );
2668 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002669 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002670 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002671 s8 dvmJitf2l( float op1 );
2672 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002673
Bill Buzbeed45ba372009-06-15 17:00:57 -07002674 switch (opCode) {
2675 case OP_INT_TO_FLOAT:
2676 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2677 case OP_FLOAT_TO_INT:
2678 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2679 case OP_DOUBLE_TO_FLOAT:
2680 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2681 case OP_FLOAT_TO_DOUBLE:
2682 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2683 case OP_INT_TO_DOUBLE:
2684 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2685 case OP_DOUBLE_TO_INT:
2686 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2687 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002688 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002689 case OP_LONG_TO_FLOAT:
2690 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2691 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002692 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002693 case OP_LONG_TO_DOUBLE:
2694 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2695 default:
2696 return true;
2697 }
2698 return false;
2699}
2700
2701static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2702{
2703 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002704 RegLocation rlDest;
2705 RegLocation rlSrc;
2706 RegLocation rlResult;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002707
Ben Chengba4fc8b2009-06-01 13:00:29 -07002708 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002709 return handleArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002710 }
2711
Bill Buzbee1465db52009-09-23 17:17:35 -07002712 if (mir->ssaRep->numUses == 2)
2713 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2714 else
2715 rlSrc = getSrcLoc(cUnit, mir, 0);
2716 if (mir->ssaRep->numDefs == 2)
2717 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2718 else
2719 rlDest = getDestLoc(cUnit, mir, 0);
Ben Chenge9695e52009-06-16 16:11:47 -07002720
Ben Chengba4fc8b2009-06-01 13:00:29 -07002721 switch (opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002722 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002723 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002724 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002725 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002726 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002727 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002728 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002729 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002730 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002731 case OP_LONG_TO_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002732 return handleConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002733 case OP_NEG_INT:
2734 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002735 return handleArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002736 case OP_NEG_LONG:
2737 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07002738 return handleArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002739 case OP_NEG_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002740 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002741 case OP_NEG_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002742 return handleArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
2743 case OP_MOVE_WIDE:
2744 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002745 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07002746 case OP_INT_TO_LONG:
2747 rlSrc = updateLoc(cUnit, rlSrc);
2748 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2749 if (rlSrc.location == kLocPhysReg) {
2750 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2751 } else {
2752 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
2753 }
2754 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2755 rlResult.lowReg, 31);
2756 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002757 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07002758 case OP_LONG_TO_INT:
2759 rlSrc = updateLocWide(cUnit, rlSrc);
2760 rlSrc = wideToNarrowLoc(cUnit, rlSrc);
2761 // Intentional fallthrough
Ben Chengba4fc8b2009-06-01 13:00:29 -07002762 case OP_MOVE:
2763 case OP_MOVE_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002764 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002765 break;
2766 case OP_INT_TO_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002767 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2768 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2769 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
2770 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002771 break;
2772 case OP_INT_TO_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002773 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2774 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2775 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
2776 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002777 break;
2778 case OP_INT_TO_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002779 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2780 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2781 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
2782 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002783 break;
2784 case OP_ARRAY_LENGTH: {
2785 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07002786 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2787 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
2788 mir->offset, NULL);
2789 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2790 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
2791 rlResult.lowReg);
2792 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002793 break;
2794 }
2795 default:
2796 return true;
2797 }
2798 return false;
2799}
2800
2801static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2802{
2803 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002804 RegLocation rlDest;
2805 RegLocation rlResult;
2806 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002807 if (dalvikOpCode == OP_CONST_WIDE_16) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002808 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2809 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2810 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
2811 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
2812 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002813 } else if (dalvikOpCode == OP_CONST_16) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002814 rlDest = getDestLoc(cUnit, mir, 0);
2815 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2816 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
2817 storeValue(cUnit, rlDest, rlResult);
2818 } else
Ben Chengba4fc8b2009-06-01 13:00:29 -07002819 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002820 return false;
2821}
2822
2823/* Compare agaist zero */
2824static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002825 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002826{
2827 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002828 ArmConditionCode cond;
Bill Buzbee1465db52009-09-23 17:17:35 -07002829 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2830 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2831 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002832
Bill Buzbee270c1d62009-08-13 16:58:07 -07002833//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002834 switch (dalvikOpCode) {
2835 case OP_IF_EQZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002836 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002837 break;
2838 case OP_IF_NEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002839 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002840 break;
2841 case OP_IF_LTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002842 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002843 break;
2844 case OP_IF_GEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002845 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002846 break;
2847 case OP_IF_GTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002848 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002849 break;
2850 case OP_IF_LEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002851 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002852 break;
2853 default:
2854 cond = 0;
2855 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2856 dvmAbort();
2857 }
2858 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2859 /* This mostly likely will be optimized away in a later phase */
2860 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2861 return false;
2862}
2863
2864static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2865{
2866 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002867 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2868 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2869 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002870 int lit = mir->dalvikInsn.vC;
Ben Cheng4f489172009-09-27 17:08:35 -07002871 OpKind op = 0; /* Make gcc happy */
Bill Buzbee1465db52009-09-23 17:17:35 -07002872 int shiftOp = false;
2873 bool isDiv = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002874
Ben Chengba4fc8b2009-06-01 13:00:29 -07002875 int __aeabi_idivmod(int op1, int op2);
2876 int __aeabi_idiv(int op1, int op2);
2877
2878 switch (dalvikOpCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002879 case OP_RSUB_INT_LIT8:
2880 case OP_RSUB_INT: {
2881 int tReg;
2882 //TUNING: add support for use of Arm rsub op
2883 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2884 tReg = allocTemp(cUnit);
2885 loadConstant(cUnit, tReg, lit);
2886 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2887 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
2888 tReg, rlSrc.lowReg);
2889 storeValue(cUnit, rlDest, rlResult);
2890 return false;
2891 break;
2892 }
2893
Ben Chengba4fc8b2009-06-01 13:00:29 -07002894 case OP_ADD_INT_LIT8:
2895 case OP_ADD_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002896 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002897 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002898 case OP_MUL_INT_LIT8:
2899 case OP_MUL_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002900 op = kOpMul;
2901 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002902 case OP_AND_INT_LIT8:
2903 case OP_AND_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002904 op = kOpAnd;
2905 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002906 case OP_OR_INT_LIT8:
2907 case OP_OR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002908 op = kOpOr;
2909 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002910 case OP_XOR_INT_LIT8:
2911 case OP_XOR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002912 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002913 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002914 case OP_SHL_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002915 shiftOp = true;
2916 op = kOpLsl;
2917 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002918 case OP_SHR_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002919 shiftOp = true;
2920 op = kOpAsr;
2921 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002922 case OP_USHR_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002923 shiftOp = true;
2924 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002925 break;
2926
2927 case OP_DIV_INT_LIT8:
2928 case OP_DIV_INT_LIT16:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002929 case OP_REM_INT_LIT8:
2930 case OP_REM_INT_LIT16:
2931 if (lit == 0) {
2932 /* Let the interpreter deal with div by 0 */
2933 genInterpSingleStep(cUnit, mir);
2934 return false;
2935 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002936 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002937 loadValueDirectFixed(cUnit, rlSrc, r0);
2938 clobberReg(cUnit, r0);
2939 if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2940 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2941 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2942 isDiv = true;
2943 } else {
2944 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2945 isDiv = false;
2946 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002947 loadConstant(cUnit, r1, lit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002948 opReg(cUnit, kOpBlx, r2);
2949 clobberCallRegs(cUnit);
2950 if (isDiv)
2951 rlResult = getReturnLoc(cUnit);
2952 else
2953 rlResult = getReturnLocAlt(cUnit);
2954 storeValue(cUnit, rlDest, rlResult);
2955 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002956 break;
2957 default:
2958 return true;
2959 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002960 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2961 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2962 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2963 if (shiftOp && (lit == 0)) {
2964 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2965 } else {
2966 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2967 }
2968 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002969 return false;
2970}
2971
2972static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2973{
2974 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2975 int fieldOffset;
2976
2977 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2978 InstField *pInstField = (InstField *)
2979 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002980
2981 assert(pInstField != NULL);
2982 fieldOffset = pInstField->byteOffset;
2983 } else {
Ben Chenga0e7b602009-10-13 23:09:01 -07002984 /* Deliberately break the code while make the compiler happy */
2985 fieldOffset = -1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002986 }
2987 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002988 case OP_NEW_ARRAY: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002989 // Generates a call - use explicit registers
2990 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2991 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2992 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002993 void *classPtr = (void*)
2994 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2995 assert(classPtr != NULL);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002996 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002997 genExportPC(cUnit, mir);
2998 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002999 loadConstant(cUnit, r0, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07003000 loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
Ben Cheng4f489172009-09-27 17:08:35 -07003001 /*
3002 * "len < 0": bail to the interpreter to re-execute the
3003 * instruction
3004 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003005 ArmLIR *pcrLabel =
Bill Buzbee1465db52009-09-23 17:17:35 -07003006 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003007 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07003008 opReg(cUnit, kOpBlx, r3);
3009 clobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07003010 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07003011 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3012 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07003013 /*
3014 * OOM exception needs to be thrown here and cannot re-execute
3015 */
3016 loadConstant(cUnit, r0,
3017 (int) (cUnit->method->insns + mir->offset));
3018 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3019 /* noreturn */
3020
Bill Buzbee1465db52009-09-23 17:17:35 -07003021 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07003022 target->defMask = ENCODE_ALL;
3023 branchOver->generic.target = (LIR *) target;
Bill Buzbee1465db52009-09-23 17:17:35 -07003024 rlResult = getReturnLoc(cUnit);
3025 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003026 break;
3027 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003028 case OP_INSTANCE_OF: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003029 // May generate a call - use explicit registers
3030 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3031 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
3032 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003033 ClassObject *classPtr =
3034 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
3035 assert(classPtr != NULL);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003036 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003037 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003038 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07003039//TUNING: compare to 0 primative to allow use of CB[N]Z
Bill Buzbee1465db52009-09-23 17:17:35 -07003040 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07003041 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee1465db52009-09-23 17:17:35 -07003042 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003043 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003044 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07003045 /* r1 now contains object->clazz */
3046 loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07003047 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee1465db52009-09-23 17:17:35 -07003048 opRegReg(cUnit, kOpCmp, r1, r2);
3049 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
3050 genRegCopy(cUnit, r0, r1);
3051 genRegCopy(cUnit, r1, r2);
3052 opReg(cUnit, kOpBlx, r3);
3053 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003054 /* branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07003055 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07003056 target->defMask = ENCODE_ALL;
Bill Buzbee1465db52009-09-23 17:17:35 -07003057 rlResult = getReturnLoc(cUnit);
3058 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003059 branch1->generic.target = (LIR *)target;
3060 branch2->generic.target = (LIR *)target;
3061 break;
3062 }
3063 case OP_IGET_WIDE:
3064 genIGetWide(cUnit, mir, fieldOffset);
3065 break;
3066 case OP_IGET:
3067 case OP_IGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003068 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003069 break;
3070 case OP_IGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003071 genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003072 break;
3073 case OP_IGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003074 genIGet(cUnit, mir, kSignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003075 break;
3076 case OP_IGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003077 genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003078 break;
3079 case OP_IGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003080 genIGet(cUnit, mir, kSignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003081 break;
3082 case OP_IPUT_WIDE:
3083 genIPutWide(cUnit, mir, fieldOffset);
3084 break;
3085 case OP_IPUT:
3086 case OP_IPUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003087 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003088 break;
3089 case OP_IPUT_SHORT:
3090 case OP_IPUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003091 genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003092 break;
3093 case OP_IPUT_BYTE:
3094 case OP_IPUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003095 genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003096 break;
3097 default:
3098 return true;
3099 }
3100 return false;
3101}
3102
3103static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
3104{
3105 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3106 int fieldOffset = mir->dalvikInsn.vC;
3107 switch (dalvikOpCode) {
3108 case OP_IGET_QUICK:
3109 case OP_IGET_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07003110 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003111 break;
3112 case OP_IPUT_QUICK:
3113 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07003114 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003115 break;
3116 case OP_IGET_WIDE_QUICK:
3117 genIGetWide(cUnit, mir, fieldOffset);
3118 break;
3119 case OP_IPUT_WIDE_QUICK:
3120 genIPutWide(cUnit, mir, fieldOffset);
3121 break;
3122 default:
3123 return true;
3124 }
3125 return false;
3126
3127}
3128
3129/* Compare agaist zero */
3130static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003131 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003132{
3133 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003134 ArmConditionCode cond;
Bill Buzbee1465db52009-09-23 17:17:35 -07003135 RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
3136 RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003137
Bill Buzbee1465db52009-09-23 17:17:35 -07003138 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
3139 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
3140 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003141
3142 switch (dalvikOpCode) {
3143 case OP_IF_EQ:
Bill Buzbee1465db52009-09-23 17:17:35 -07003144 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003145 break;
3146 case OP_IF_NE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003147 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003148 break;
3149 case OP_IF_LT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003150 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003151 break;
3152 case OP_IF_GE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003153 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003154 break;
3155 case OP_IF_GT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003156 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003157 break;
3158 case OP_IF_LE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003159 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003160 break;
3161 default:
3162 cond = 0;
3163 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
3164 dvmAbort();
3165 }
3166 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
3167 /* This mostly likely will be optimized away in a later phase */
3168 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
3169 return false;
3170}
3171
3172static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
3173{
3174 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003175
3176 switch (opCode) {
3177 case OP_MOVE_16:
3178 case OP_MOVE_OBJECT_16:
3179 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07003180 case OP_MOVE_OBJECT_FROM16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003181 storeValue(cUnit, getDestLoc(cUnit, mir, 0),
3182 getSrcLoc(cUnit, mir, 0));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003183 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003184 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003185 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07003186 case OP_MOVE_WIDE_FROM16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003187 storeValueWide(cUnit, getDestLocWide(cUnit, mir, 0, 1),
3188 getSrcLocWide(cUnit, mir, 0, 1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003189 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003190 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003191 default:
3192 return true;
3193 }
3194 return false;
3195}
3196
3197static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
3198{
3199 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07003200 RegLocation rlSrc1;
3201 RegLocation rlSrc2;
3202 RegLocation rlDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003203
3204 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003205 return handleArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07003206 }
3207
Bill Buzbee1465db52009-09-23 17:17:35 -07003208 /* APUTs have 3 sources and no targets */
3209 if (mir->ssaRep->numDefs == 0) {
3210 if (mir->ssaRep->numUses == 3) {
3211 rlDest = getSrcLoc(cUnit, mir, 0);
3212 rlSrc1 = getSrcLoc(cUnit, mir, 1);
3213 rlSrc2 = getSrcLoc(cUnit, mir, 2);
3214 } else {
3215 assert(mir->ssaRep->numUses == 4);
3216 rlDest = getSrcLocWide(cUnit, mir, 0, 1);
3217 rlSrc1 = getSrcLoc(cUnit, mir, 2);
3218 rlSrc2 = getSrcLoc(cUnit, mir, 3);
3219 }
3220 } else {
3221 /* Two sources and 1 dest. Deduce the operand sizes */
3222 if (mir->ssaRep->numUses == 4) {
3223 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
3224 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
3225 } else {
3226 assert(mir->ssaRep->numUses == 2);
3227 rlSrc1 = getSrcLoc(cUnit, mir, 0);
3228 rlSrc2 = getSrcLoc(cUnit, mir, 1);
3229 }
3230 if (mir->ssaRep->numDefs == 2) {
3231 rlDest = getDestLocWide(cUnit, mir, 0, 1);
3232 } else {
3233 assert(mir->ssaRep->numDefs == 1);
3234 rlDest = getDestLoc(cUnit, mir, 0);
3235 }
3236 }
3237
3238
Ben Chengba4fc8b2009-06-01 13:00:29 -07003239 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07003240 case OP_CMPL_FLOAT:
3241 case OP_CMPG_FLOAT:
3242 case OP_CMPL_DOUBLE:
3243 case OP_CMPG_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003244 return handleCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003245 case OP_CMP_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07003246 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003247 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003248 case OP_AGET_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003249 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003250 break;
3251 case OP_AGET:
3252 case OP_AGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003253 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003254 break;
3255 case OP_AGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003256 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003257 break;
3258 case OP_AGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003259 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003260 break;
3261 case OP_AGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003262 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003263 break;
3264 case OP_AGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003265 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003266 break;
3267 case OP_APUT_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003268 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003269 break;
3270 case OP_APUT:
3271 case OP_APUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003272 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003273 break;
3274 case OP_APUT_SHORT:
3275 case OP_APUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003276 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003277 break;
3278 case OP_APUT_BYTE:
3279 case OP_APUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003280 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003281 break;
3282 default:
3283 return true;
3284 }
3285 return false;
3286}
3287
Ben Cheng6c10a972009-10-29 14:39:18 -07003288/*
3289 * Find the matching case.
3290 *
3291 * return values:
3292 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
3293 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
3294 * r1 (high 32-bit): the branch offset of the matching case (only for indexes
3295 * above MAX_CHAINED_SWITCH_CASES).
3296 *
3297 * Instructions around the call are:
3298 *
3299 * mov r2, pc
3300 * blx &findPackedSwitchIndex
3301 * mov pc, r0
3302 * .align4
3303 * chaining cell for case 0 [8 bytes]
3304 * chaining cell for case 1 [8 bytes]
3305 * :
3306 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
3307 * chaining cell for case default [8 bytes]
3308 * noChain exit
3309 */
3310s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
3311{
3312 int size;
3313 int firstKey;
3314 const int *entries;
3315 int index;
3316 int jumpIndex;
3317 int caseDPCOffset = 0;
3318 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
3319 int chainingPC = (pc + 4) & ~3;
3320
3321 /*
3322 * Packed switch data format:
3323 * ushort ident = 0x0100 magic value
3324 * ushort size number of entries in the table
3325 * int first_key first (and lowest) switch case value
3326 * int targets[size] branch targets, relative to switch opcode
3327 *
3328 * Total size is (4+size*2) 16-bit code units.
3329 */
3330 size = switchData[1];
3331 assert(size > 0);
3332
3333 firstKey = switchData[2];
3334 firstKey |= switchData[3] << 16;
3335
3336
3337 /* The entries are guaranteed to be aligned on a 32-bit boundary;
3338 * we can treat them as a native int array.
3339 */
3340 entries = (const int*) &switchData[4];
3341 assert(((u4)entries & 0x3) == 0);
3342
3343 index = testVal - firstKey;
3344
3345 /* Jump to the default cell */
3346 if (index < 0 || index >= size) {
3347 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
3348 /* Jump to the non-chaining exit point */
3349 } else if (index >= MAX_CHAINED_SWITCH_CASES) {
3350 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
3351 caseDPCOffset = entries[index];
3352 /* Jump to the inline chaining cell */
3353 } else {
3354 jumpIndex = index;
3355 }
3356
3357 chainingPC += jumpIndex * 8;
3358 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
3359}
3360
3361/* See comments for findPackedSwitchIndex */
3362s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
3363{
3364 int size;
3365 const int *keys;
3366 const int *entries;
3367 int chainingPC = (pc + 4) & ~3;
3368 int i;
3369
3370 /*
3371 * Sparse switch data format:
3372 * ushort ident = 0x0200 magic value
3373 * ushort size number of entries in the table; > 0
3374 * int keys[size] keys, sorted low-to-high; 32-bit aligned
3375 * int targets[size] branch targets, relative to switch opcode
3376 *
3377 * Total size is (2+size*4) 16-bit code units.
3378 */
3379
3380 size = switchData[1];
3381 assert(size > 0);
3382
3383 /* The keys are guaranteed to be aligned on a 32-bit boundary;
3384 * we can treat them as a native int array.
3385 */
3386 keys = (const int*) &switchData[2];
3387 assert(((u4)keys & 0x3) == 0);
3388
3389 /* The entries are guaranteed to be aligned on a 32-bit boundary;
3390 * we can treat them as a native int array.
3391 */
3392 entries = keys + size;
3393 assert(((u4)entries & 0x3) == 0);
3394
3395 /*
3396 * Run through the list of keys, which are guaranteed to
3397 * be sorted low-to-high.
3398 *
3399 * Most tables have 3-4 entries. Few have more than 10. A binary
3400 * search here is probably not useful.
3401 */
3402 for (i = 0; i < size; i++) {
3403 int k = keys[i];
3404 if (k == testVal) {
3405 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
3406 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
3407 i : MAX_CHAINED_SWITCH_CASES + 1;
3408 chainingPC += jumpIndex * 8;
3409 return (((s8) entries[i]) << 32) | (u8) chainingPC;
3410 } else if (k > testVal) {
3411 break;
3412 }
3413 }
3414 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
3415}
3416
Ben Chengba4fc8b2009-06-01 13:00:29 -07003417static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
3418{
3419 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3420 switch (dalvikOpCode) {
3421 case OP_FILL_ARRAY_DATA: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003422 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3423 // Making a call - use explicit registers
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003424 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003425 genExportPC(cUnit, mir);
3426 loadValueDirectFixed(cUnit, rlSrc, r0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003427 loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData);
Ben Cheng6c10a972009-10-29 14:39:18 -07003428 loadConstant(cUnit, r1,
3429 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
Bill Buzbee1465db52009-09-23 17:17:35 -07003430 opReg(cUnit, kOpBlx, r2);
3431 clobberCallRegs(cUnit);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003432 /* generate a branch over if successful */
3433 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3434 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3435 loadConstant(cUnit, r0,
3436 (int) (cUnit->method->insns + mir->offset));
3437 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3438 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3439 target->defMask = ENCODE_ALL;
3440 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003441 break;
3442 }
3443 /*
Ben Cheng6c10a972009-10-29 14:39:18 -07003444 * Compute the goto target of up to
3445 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
3446 * See the comment before findPackedSwitchIndex for the code layout.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003447 */
3448 case OP_PACKED_SWITCH:
3449 case OP_SPARSE_SWITCH: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003450 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003451 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003452 loadValueDirectFixed(cUnit, rlSrc, r1);
3453 lockAllTemps(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07003454 const u2 *switchData =
3455 cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
3456 u2 size = switchData[1];
3457
Ben Chengba4fc8b2009-06-01 13:00:29 -07003458 if (dalvikOpCode == OP_PACKED_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -07003459 loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003460 } else {
Ben Cheng6c10a972009-10-29 14:39:18 -07003461 loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003462 }
Ben Cheng6c10a972009-10-29 14:39:18 -07003463 /* r0 <- Addr of the switch data */
3464 loadConstant(cUnit, r0,
3465 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
3466 /* r2 <- pc of the instruction following the blx */
3467 opRegReg(cUnit, kOpMov, r2, rpc);
Bill Buzbee1465db52009-09-23 17:17:35 -07003468 opReg(cUnit, kOpBlx, r4PC);
3469 clobberCallRegs(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07003470 /* pc <- computed goto target */
3471 opRegReg(cUnit, kOpMov, rpc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003472 break;
3473 }
3474 default:
3475 return true;
3476 }
3477 return false;
3478}
3479
3480static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003481 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003482{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003483 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003484 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003485
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003486 if (bb->fallThrough != NULL)
3487 retChainingCell = &labelList[bb->fallThrough->id];
3488
Ben Chengba4fc8b2009-06-01 13:00:29 -07003489 DecodedInstruction *dInsn = &mir->dalvikInsn;
3490 switch (mir->dalvikInsn.opCode) {
3491 /*
3492 * calleeMethod = this->clazz->vtable[
3493 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3494 * ]
3495 */
3496 case OP_INVOKE_VIRTUAL:
3497 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003498 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003499 int methodIndex =
3500 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3501 methodIndex;
3502
3503 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3504 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3505 else
3506 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3507
Ben Cheng38329f52009-07-07 14:19:20 -07003508 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3509 retChainingCell,
3510 predChainingCell,
3511 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003512 break;
3513 }
3514 /*
3515 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3516 * ->pResMethods[BBBB]->methodIndex]
3517 */
3518 /* TODO - not excersized in RunPerf.jar */
3519 case OP_INVOKE_SUPER:
3520 case OP_INVOKE_SUPER_RANGE: {
3521 int mIndex = cUnit->method->clazz->pDvmDex->
3522 pResMethods[dInsn->vB]->methodIndex;
3523 const Method *calleeMethod =
3524 cUnit->method->clazz->super->vtable[mIndex];
3525
3526 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3527 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3528 else
3529 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3530
3531 /* r0 = calleeMethod */
3532 loadConstant(cUnit, r0, (int) calleeMethod);
3533
Ben Cheng38329f52009-07-07 14:19:20 -07003534 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3535 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003536 break;
3537 }
3538 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3539 case OP_INVOKE_DIRECT:
3540 case OP_INVOKE_DIRECT_RANGE: {
3541 const Method *calleeMethod =
3542 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3543
3544 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3545 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3546 else
3547 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3548
3549 /* r0 = calleeMethod */
3550 loadConstant(cUnit, r0, (int) calleeMethod);
3551
Ben Cheng38329f52009-07-07 14:19:20 -07003552 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3553 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003554 break;
3555 }
3556 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3557 case OP_INVOKE_STATIC:
3558 case OP_INVOKE_STATIC_RANGE: {
3559 const Method *calleeMethod =
3560 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3561
3562 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3563 genProcessArgsNoRange(cUnit, mir, dInsn,
3564 NULL /* no null check */);
3565 else
3566 genProcessArgsRange(cUnit, mir, dInsn,
3567 NULL /* no null check */);
3568
3569 /* r0 = calleeMethod */
3570 loadConstant(cUnit, r0, (int) calleeMethod);
3571
Ben Cheng38329f52009-07-07 14:19:20 -07003572 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3573 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003574 break;
3575 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003576 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -07003577 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3578 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003579 *
3580 * Given "invoke-interface {v0}", the following is the generated code:
3581 *
3582 * 0x426a9abe : ldr r0, [r5, #0] --+
3583 * 0x426a9ac0 : mov r7, r5 |
3584 * 0x426a9ac2 : sub r7, #24 |
3585 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3586 * 0x426a9ac6 : beq 0x426a9afe |
3587 * 0x426a9ac8 : stmia r7, <r0> --+
3588 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3589 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3590 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3591 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3592 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3593 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3594 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
Ben Chenga8e64a72009-10-20 13:01:36 -07003595 * 0x426a9ad8 : mov r8, r1 --+
3596 * 0x426a9ada : mov r9, r2 |
3597 * 0x426a9adc : mov r10, r3 |
Ben Cheng38329f52009-07-07 14:19:20 -07003598 * 0x426a9ade : mov r0, r3 |
3599 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3600 * 0x426a9ae2 : ldr r2, [pc, #76] |
3601 * 0x426a9ae4 : ldr r3, [pc, #68] |
3602 * 0x426a9ae6 : ldr r7, [pc, #64] |
3603 * 0x426a9ae8 : blx r7 --+
Ben Chenga8e64a72009-10-20 13:01:36 -07003604 * 0x426a9aea : mov r1, r8 --> r1 <- rechain count
Ben Cheng38329f52009-07-07 14:19:20 -07003605 * 0x426a9aec : cmp r1, #0 --> compare against 0
3606 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3607 * 0x426a9af0 : ldr r7, [r6, #96] --+
Ben Chenga8e64a72009-10-20 13:01:36 -07003608 * 0x426a9af2 : mov r2, r9 | dvmJitToPatchPredictedChain
3609 * 0x426a9af4 : mov r3, r10 |
Ben Cheng38329f52009-07-07 14:19:20 -07003610 * 0x426a9af6 : blx r7 --+
3611 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3612 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3613 * 0x426a9afc : blx_2 see above --+
3614 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3615 * 0x426a9afe (0042): ldr r0, [pc, #52]
3616 * Exception_Handling:
3617 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3618 * 0x426a9b02 (0046): blx r1
3619 * 0x426a9b04 (0048): .align4
3620 * -------- chaining cell (hot): 0x0021
3621 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3622 * 0x426a9b06 (004a): blx r0
3623 * 0x426a9b08 (004c): data 0x7872(30834)
3624 * 0x426a9b0a (004e): data 0x428b(17035)
3625 * 0x426a9b0c (0050): .align4
3626 * -------- chaining cell (predicted)
3627 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3628 * 0x426a9b0e (0052): data 0x0000(0)
3629 * 0x426a9b10 (0054): data 0x0000(0) --> class
3630 * 0x426a9b12 (0056): data 0x0000(0)
3631 * 0x426a9b14 (0058): data 0x0000(0) --> method
3632 * 0x426a9b16 (005a): data 0x0000(0)
3633 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3634 * 0x426a9b1a (005e): data 0x0000(0)
3635 * 0x426a9b28 (006c): .word (0xad0392a5)
3636 * 0x426a9b2c (0070): .word (0x6e750)
3637 * 0x426a9b30 (0074): .word (0x4109a618)
3638 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003639 */
3640 case OP_INVOKE_INTERFACE:
3641 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003642 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003643 int methodIndex = dInsn->vB;
3644
Bill Buzbee1465db52009-09-23 17:17:35 -07003645 /* Ensure that nothing is both live and dirty */
3646 flushAllRegs(cUnit);
3647
Ben Chengba4fc8b2009-06-01 13:00:29 -07003648 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3649 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3650 else
3651 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3652
Ben Cheng38329f52009-07-07 14:19:20 -07003653 /* "this" is already left in r0 by genProcessArgs* */
3654
3655 /* r4PC = dalvikCallsite */
3656 loadConstant(cUnit, r4PC,
3657 (int) (cUnit->method->insns + mir->offset));
3658
3659 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003660 ArmLIR *addrRetChain =
Bill Buzbee1465db52009-09-23 17:17:35 -07003661 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003662 addrRetChain->generic.target = (LIR *) retChainingCell;
3663
3664 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003665 ArmLIR *predictedChainingCell =
Bill Buzbee1465db52009-09-23 17:17:35 -07003666 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003667 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3668
3669 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3670
3671 /* return through lr - jump to the chaining cell */
3672 genUnconditionalBranch(cUnit, predChainingCell);
3673
3674 /*
3675 * null-check on "this" may have been eliminated, but we still need
3676 * a PC-reconstruction label for stack overflow bailout.
3677 */
3678 if (pcrLabel == NULL) {
3679 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003680 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003681 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003682 pcrLabel->operands[0] = dPC;
3683 pcrLabel->operands[1] = mir->offset;
3684 /* Insert the place holder to the growable list */
3685 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3686 }
3687
3688 /* return through lr+2 - punt to the interpreter */
3689 genUnconditionalBranch(cUnit, pcrLabel);
3690
3691 /*
3692 * return through lr+4 - fully resolve the callee method.
3693 * r1 <- count
3694 * r2 <- &predictedChainCell
3695 * r3 <- this->class
3696 * r4 <- dPC
3697 * r7 <- this->class->vtable
3698 */
3699
3700 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee1465db52009-09-23 17:17:35 -07003701 genRegCopy(cUnit, r8, r1);
3702 genRegCopy(cUnit, r9, r2);
3703 genRegCopy(cUnit, r10, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003704
Ben Chengba4fc8b2009-06-01 13:00:29 -07003705 /* r0 now contains this->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07003706 genRegCopy(cUnit, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003707
3708 /* r1 = BBBB */
3709 loadConstant(cUnit, r1, dInsn->vB);
3710
3711 /* r2 = method (caller) */
3712 loadConstant(cUnit, r2, (int) cUnit->method);
3713
3714 /* r3 = pDvmDex */
3715 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3716
3717 loadConstant(cUnit, r7,
3718 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee1465db52009-09-23 17:17:35 -07003719 opReg(cUnit, kOpBlx, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003720
3721 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3722
Bill Buzbee1465db52009-09-23 17:17:35 -07003723 genRegCopy(cUnit, r1, r8);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003724
Ben Cheng38329f52009-07-07 14:19:20 -07003725 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07003726 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003727
Bill Buzbee1465db52009-09-23 17:17:35 -07003728 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07003729
Bill Buzbee270c1d62009-08-13 16:58:07 -07003730 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3731 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003732
Bill Buzbee1465db52009-09-23 17:17:35 -07003733 genRegCopy(cUnit, r2, r9);
3734 genRegCopy(cUnit, r3, r10);
Ben Cheng38329f52009-07-07 14:19:20 -07003735
3736 /*
3737 * r0 = calleeMethod
3738 * r2 = &predictedChainingCell
3739 * r3 = class
3740 *
3741 * &returnChainingCell has been loaded into r1 but is not needed
3742 * when patching the chaining cell and will be clobbered upon
3743 * returning so it will be reconstructed again.
3744 */
Bill Buzbee1465db52009-09-23 17:17:35 -07003745 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003746
3747 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07003748 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003749 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003750
3751 bypassRechaining->generic.target = (LIR *) addrRetChain;
3752
Ben Chengba4fc8b2009-06-01 13:00:29 -07003753 /*
3754 * r0 = this, r1 = calleeMethod,
3755 * r1 = &ChainingCell,
3756 * r4PC = callsiteDPC,
3757 */
3758 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3759#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003760 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003761#endif
3762 /* Handle exceptions using the interpreter */
3763 genTrap(cUnit, mir->offset, pcrLabel);
3764 break;
3765 }
3766 /* NOP */
3767 case OP_INVOKE_DIRECT_EMPTY: {
3768 return false;
3769 }
3770 case OP_FILLED_NEW_ARRAY:
3771 case OP_FILLED_NEW_ARRAY_RANGE: {
3772 /* Just let the interpreter deal with these */
3773 genInterpSingleStep(cUnit, mir);
3774 break;
3775 }
3776 default:
3777 return true;
3778 }
3779 return false;
3780}
3781
3782static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003783 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003784{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003785 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3786 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3787 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003788
3789 DecodedInstruction *dInsn = &mir->dalvikInsn;
3790 switch (mir->dalvikInsn.opCode) {
3791 /* calleeMethod = this->clazz->vtable[BBBB] */
3792 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3793 case OP_INVOKE_VIRTUAL_QUICK: {
3794 int methodIndex = dInsn->vB;
3795 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3796 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3797 else
3798 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3799
Ben Cheng38329f52009-07-07 14:19:20 -07003800 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3801 retChainingCell,
3802 predChainingCell,
3803 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003804 break;
3805 }
3806 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3807 case OP_INVOKE_SUPER_QUICK:
3808 case OP_INVOKE_SUPER_QUICK_RANGE: {
3809 const Method *calleeMethod =
3810 cUnit->method->clazz->super->vtable[dInsn->vB];
3811
3812 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3813 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3814 else
3815 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3816
3817 /* r0 = calleeMethod */
3818 loadConstant(cUnit, r0, (int) calleeMethod);
3819
Ben Cheng38329f52009-07-07 14:19:20 -07003820 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3821 calleeMethod);
3822 /* Handle exceptions using the interpreter */
3823 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003824 break;
3825 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003826 default:
3827 return true;
3828 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003829 return false;
3830}
3831
3832/*
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003833 * This operation is complex enough that we'll do it partly inline
3834 * and partly with a handler. NOTE: the handler uses hardcoded
3835 * values for string object offsets and must be revisitied if the
3836 * layout changes.
3837 */
3838static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
3839{
3840#if defined(USE_GLOBAL_STRING_DEFS)
3841 return false;
3842#else
3843 ArmLIR *rollback;
3844 RegLocation rlThis = getSrcLoc(cUnit, mir, 0);
3845 RegLocation rlComp = getSrcLoc(cUnit, mir, 1);
3846
3847 loadValueDirectFixed(cUnit, rlThis, r0);
3848 loadValueDirectFixed(cUnit, rlComp, r1);
3849 /* Test objects for NULL */
3850 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3851 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
3852 /*
3853 * TUNING: we could check for object pointer equality before invoking
3854 * handler. Unclear whether the gain would be worth the added code size
3855 * expansion.
3856 */
3857 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
3858 storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit));
3859 return true;
3860#endif
3861}
3862
3863static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
3864{
3865#if defined(USE_GLOBAL_STRING_DEFS)
3866 return false;
3867#else
3868 RegLocation rlThis = getSrcLoc(cUnit, mir, 0);
3869 RegLocation rlChar = getSrcLoc(cUnit, mir, 1);
3870
3871 loadValueDirectFixed(cUnit, rlThis, r0);
3872 loadValueDirectFixed(cUnit, rlChar, r1);
3873 if (!singleI) {
3874 RegLocation rlStart = getSrcLoc(cUnit, mir, 2);
3875 loadValueDirectFixed(cUnit, rlStart, r2);
3876 } else {
3877 loadConstant(cUnit, r2, 0);
3878 }
3879 /* Test objects for NULL */
3880 genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3881 genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
3882 storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit));
3883 return true;
3884#endif
3885}
3886
3887
3888/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07003889 * NOTE: We assume here that the special native inline routines
3890 * are side-effect free. By making this assumption, we can safely
3891 * re-execute the routine from the interpreter if it decides it
3892 * wants to throw an exception. We still need to EXPORT_PC(), though.
3893 */
3894static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3895{
3896 DecodedInstruction *dInsn = &mir->dalvikInsn;
3897 switch( mir->dalvikInsn.opCode) {
3898 case OP_EXECUTE_INLINE: {
3899 unsigned int i;
3900 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003901 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003902 int operation = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07003903 int tReg1;
3904 int tReg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003905 switch (operation) {
3906 case INLINE_EMPTYINLINEMETHOD:
3907 return false; /* Nop */
3908 case INLINE_STRING_LENGTH:
3909 return genInlinedStringLength(cUnit, mir);
3910 case INLINE_MATH_ABS_INT:
3911 return genInlinedAbsInt(cUnit, mir);
3912 case INLINE_MATH_ABS_LONG:
3913 return genInlinedAbsLong(cUnit, mir);
3914 case INLINE_MATH_MIN_INT:
3915 return genInlinedMinMaxInt(cUnit, mir, true);
3916 case INLINE_MATH_MAX_INT:
3917 return genInlinedMinMaxInt(cUnit, mir, false);
3918 case INLINE_STRING_CHARAT:
3919 return genInlinedStringCharAt(cUnit, mir);
3920 case INLINE_MATH_SQRT:
3921 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003922 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003923 else
3924 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003925 case INLINE_MATH_ABS_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003926 if (genInlinedAbsFloat(cUnit, mir))
3927 return false;
3928 else
3929 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003930 case INLINE_MATH_ABS_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003931 if (genInlinedAbsDouble(cUnit, mir))
3932 return false;
3933 else
3934 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003935 case INLINE_STRING_COMPARETO:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003936 if (genInlinedCompareTo(cUnit, mir))
3937 return false;
3938 else
3939 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003940 case INLINE_STRING_INDEXOF_I:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003941 if (genInlinedIndexOf(cUnit, mir, true /* I */))
3942 return false;
3943 else
3944 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003945 case INLINE_STRING_INDEXOF_II:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003946 if (genInlinedIndexOf(cUnit, mir, false /* I */))
3947 return false;
3948 else
3949 break;
3950 case INLINE_STRING_EQUALS:
3951 case INLINE_MATH_COS:
3952 case INLINE_MATH_SIN:
3953 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003954 default:
3955 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003956 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003957 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003958 clobberCallRegs(cUnit);
3959 clobberReg(cUnit, r4PC);
3960 clobberReg(cUnit, r7);
3961 opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3962 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003963 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
Bill Buzbee1465db52009-09-23 17:17:35 -07003964 genExportPC(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003965 for (i=0; i < dInsn->vA; i++) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003966 loadValueDirect(cUnit, getSrcLoc(cUnit, mir, i), i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003967 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003968 opReg(cUnit, kOpBlx, r4PC);
3969 opRegImm(cUnit, kOpAdd, r13, 8);
Ben Chenge9695e52009-06-16 16:11:47 -07003970 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003971 break;
3972 }
3973 default:
3974 return true;
3975 }
3976 return false;
3977}
3978
3979static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3980{
Bill Buzbee1465db52009-09-23 17:17:35 -07003981 //TUNING: We're using core regs here - not optimal when target is a double
3982 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
3983 RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
3984 loadConstantValue(cUnit, rlResult.lowReg,
3985 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3986 loadConstantValue(cUnit, rlResult.highReg,
3987 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3988 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003989 return false;
3990}
3991
Ben Chengba4fc8b2009-06-01 13:00:29 -07003992/*
3993 * The following are special processing routines that handle transfer of
3994 * controls between compiled code and the interpreter. Certain VM states like
3995 * Dalvik PC and special-purpose registers are reconstructed here.
3996 */
3997
Ben Cheng1efc9c52009-06-08 18:25:27 -07003998/* Chaining cell for code that may need warmup. */
3999static void handleNormalChainingCell(CompilationUnit *cUnit,
4000 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004001{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004002 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4003 jitToInterpEntries.dvmJitToInterpNormal), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004004 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004005 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4006}
4007
4008/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07004009 * Chaining cell for instructions that immediately following already translated
4010 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07004011 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07004012static void handleHotChainingCell(CompilationUnit *cUnit,
4013 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004014{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004015 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4016 jitToInterpEntries.dvmJitToTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004017 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004018 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4019}
4020
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004021#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07004022/* Chaining cell for branches that branch back into the same basic block */
4023static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
4024 unsigned int offset)
4025{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004026#if defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07004027 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Jeff Hao97319a82009-08-12 16:57:15 -07004028 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004029#else
Bill Buzbee1465db52009-09-23 17:17:35 -07004030 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004031 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
4032#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07004033 newLIR1(cUnit, kThumbBlxR, r0);
Jeff Hao97319a82009-08-12 16:57:15 -07004034 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4035}
4036
4037#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004038/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07004039static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
4040 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004041{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004042 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4043 jitToInterpEntries.dvmJitToTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004044 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004045 addWordData(cUnit, (int) (callee->insns), true);
4046}
4047
Ben Cheng38329f52009-07-07 14:19:20 -07004048/* Chaining cell for monomorphic method invocations. */
4049static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
4050{
4051
4052 /* Should not be executed in the initial state */
4053 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
4054 /* To be filled: class */
4055 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
4056 /* To be filled: method */
4057 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
4058 /*
4059 * Rechain count. The initial value of 0 here will trigger chaining upon
4060 * the first invocation of this callsite.
4061 */
4062 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
4063}
4064
Ben Chengba4fc8b2009-06-01 13:00:29 -07004065/* Load the Dalvik PC into r0 and jump to the specified target */
4066static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004067 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004068{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004069 ArmLIR **pcrLabel =
4070 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004071 int numElems = cUnit->pcReconstructionList.numUsed;
4072 int i;
4073 for (i = 0; i < numElems; i++) {
4074 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
4075 /* r0 = dalvik PC */
4076 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
4077 genUnconditionalBranch(cUnit, targetLabel);
4078 }
4079}
4080
Bill Buzbee1465db52009-09-23 17:17:35 -07004081static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
4082 "kMirOpPhi",
4083 "kMirOpNullNRangeUpCheck",
4084 "kMirOpNullNRangeDownCheck",
4085 "kMirOpLowerBound",
4086 "kMirOpPunt",
Ben Cheng4238ec22009-08-24 16:32:22 -07004087};
4088
4089/*
4090 * vA = arrayReg;
4091 * vB = idxReg;
4092 * vC = endConditionReg;
4093 * arg[0] = maxC
4094 * arg[1] = minC
4095 * arg[2] = loopBranchConditionCode
4096 */
4097static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
4098{
Bill Buzbee1465db52009-09-23 17:17:35 -07004099 /*
4100 * NOTE: these synthesized blocks don't have ssa names assigned
4101 * for Dalvik registers. However, because they dominate the following
4102 * blocks we can simply use the Dalvik name w/ subscript 0 as the
4103 * ssa name.
4104 */
Ben Cheng4238ec22009-08-24 16:32:22 -07004105 DecodedInstruction *dInsn = &mir->dalvikInsn;
4106 const int lenOffset = offsetof(ArrayObject, length);
Ben Cheng4238ec22009-08-24 16:32:22 -07004107 const int maxC = dInsn->arg[0];
4108 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07004109 int regLength;
4110 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
4111 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
Ben Cheng4238ec22009-08-24 16:32:22 -07004112
4113 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07004114 rlArray = loadValue(cUnit, rlArray, kCoreReg);
4115 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
4116 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004117 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4118
4119 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07004120 regLength = allocTemp(cUnit);
4121 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07004122
4123 int delta = maxC;
4124 /*
4125 * If the loop end condition is ">=" instead of ">", then the largest value
4126 * of the index is "endCondition - 1".
4127 */
4128 if (dInsn->arg[2] == OP_IF_GE) {
4129 delta--;
4130 }
4131
4132 if (delta) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004133 int tReg = allocTemp(cUnit);
4134 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
4135 rlIdxEnd.lowReg = tReg;
4136 freeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004137 }
4138 /* Punt if "regIdxEnd < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004139 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07004140 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004141}
4142
4143/*
4144 * vA = arrayReg;
4145 * vB = idxReg;
4146 * vC = endConditionReg;
4147 * arg[0] = maxC
4148 * arg[1] = minC
4149 * arg[2] = loopBranchConditionCode
4150 */
4151static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
4152{
4153 DecodedInstruction *dInsn = &mir->dalvikInsn;
4154 const int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07004155 const int regLength = allocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07004156 const int maxC = dInsn->arg[0];
4157 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07004158 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
4159 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
Ben Cheng4238ec22009-08-24 16:32:22 -07004160
4161 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07004162 rlArray = loadValue(cUnit, rlArray, kCoreReg);
4163 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
4164 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004165 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4166
4167 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07004168 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07004169
4170 if (maxC) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004171 int tReg = allocTemp(cUnit);
4172 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
4173 rlIdxInit.lowReg = tReg;
4174 freeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004175 }
4176
4177 /* Punt if "regIdxInit < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004178 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07004179 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004180}
4181
4182/*
4183 * vA = idxReg;
4184 * vB = minC;
4185 */
4186static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
4187{
4188 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -07004189 const int minC = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07004190 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
Ben Cheng4238ec22009-08-24 16:32:22 -07004191
4192 /* regIdx <- initial index value */
Bill Buzbee1465db52009-09-23 17:17:35 -07004193 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004194
4195 /* Punt if "regIdxInit + minC >= 0" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004196 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004197 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4198}
4199
4200/* Extended MIR instructions like PHI */
4201static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
4202{
Bill Buzbee1465db52009-09-23 17:17:35 -07004203 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
Ben Cheng4238ec22009-08-24 16:32:22 -07004204 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
4205 false);
4206 strcpy(msg, extendedMIROpNames[opOffset]);
Bill Buzbee1465db52009-09-23 17:17:35 -07004207 newLIR1(cUnit, kArmPseudoExtended, (int) msg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004208
4209 switch (mir->dalvikInsn.opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004210 case kMirOpPhi: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004211 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07004212 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07004213 break;
4214 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004215 case kMirOpNullNRangeUpCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004216 genHoistedChecksForCountUpLoop(cUnit, mir);
4217 break;
4218 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004219 case kMirOpNullNRangeDownCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004220 genHoistedChecksForCountDownLoop(cUnit, mir);
4221 break;
4222 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004223 case kMirOpLowerBound: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004224 genHoistedLowerBoundCheck(cUnit, mir);
4225 break;
4226 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004227 case kMirOpPunt: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004228 genUnconditionalBranch(cUnit,
4229 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4230 break;
4231 }
4232 default:
4233 break;
4234 }
4235}
4236
4237/*
4238 * Create a PC-reconstruction cell for the starting offset of this trace.
4239 * Since the PCR cell is placed near the end of the compiled code which is
4240 * usually out of range for a conditional branch, we put two branches (one
4241 * branch over to the loop body and one layover branch to the actual PCR) at the
4242 * end of the entry block.
4243 */
4244static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
4245 ArmLIR *bodyLabel)
4246{
4247 /* Set up the place holder to reconstruct this Dalvik PC */
4248 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004249 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng4238ec22009-08-24 16:32:22 -07004250 pcrLabel->operands[0] =
4251 (int) (cUnit->method->insns + entry->startOffset);
4252 pcrLabel->operands[1] = entry->startOffset;
4253 /* Insert the place holder to the growable list */
4254 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
4255
4256 /*
4257 * Next, create two branches - one branch over to the loop body and the
4258 * other branch to the PCR cell to punt.
4259 */
4260 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004261 branchToBody->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07004262 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07004263 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07004264 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
4265
4266 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004267 branchToPCR->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07004268 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07004269 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004270 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
4271}
4272
Ben Chengba4fc8b2009-06-01 13:00:29 -07004273void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
4274{
4275 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004276 ArmLIR *labelList =
4277 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004278 GrowableList chainingListByType[kChainingCellLast];
Ben Chengba4fc8b2009-06-01 13:00:29 -07004279 int i;
4280
4281 /*
Ben Cheng38329f52009-07-07 14:19:20 -07004282 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07004283 */
Bill Buzbee1465db52009-09-23 17:17:35 -07004284 for (i = 0; i < kChainingCellLast; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004285 dvmInitGrowableList(&chainingListByType[i], 2);
4286 }
4287
4288 BasicBlock **blockList = cUnit->blockList;
4289
Bill Buzbee6e963e12009-06-17 16:56:19 -07004290 if (cUnit->executionCount) {
4291 /*
4292 * Reserve 6 bytes at the beginning of the trace
4293 * +----------------------------+
4294 * | execution count (4 bytes) |
4295 * +----------------------------+
4296 * | chain cell offset (2 bytes)|
4297 * +----------------------------+
4298 * ...and then code to increment the execution
4299 * count:
4300 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
4301 * sub r0, #10 @ back up to addr of executionCount
4302 * ldr r1, [r0]
4303 * add r1, #1
4304 * str r1, [r0]
4305 */
Bill Buzbee1465db52009-09-23 17:17:35 -07004306 newLIR1(cUnit, kArm16BitData, 0);
4307 newLIR1(cUnit, kArm16BitData, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07004308 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004309 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004310 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07004311 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee1465db52009-09-23 17:17:35 -07004312 newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
4313 newLIR2(cUnit, kThumbSubRI8, r0, 10);
4314 newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
4315 newLIR2(cUnit, kThumbAddRI8, r1, 1);
4316 newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004317 } else {
4318 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07004319 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004320 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004321 cUnit->headerSize = 2;
4322 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07004323
Ben Chengba4fc8b2009-06-01 13:00:29 -07004324 /* Handle the content in each basic block */
4325 for (i = 0; i < cUnit->numBlocks; i++) {
4326 blockList[i]->visited = true;
4327 MIR *mir;
4328
4329 labelList[i].operands[0] = blockList[i]->startOffset;
4330
Bill Buzbee1465db52009-09-23 17:17:35 -07004331 if (blockList[i]->blockType >= kChainingCellLast) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004332 /*
4333 * Append the label pseudo LIR first. Chaining cells will be handled
4334 * separately afterwards.
4335 */
4336 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
4337 }
4338
Bill Buzbee1465db52009-09-23 17:17:35 -07004339 if (blockList[i]->blockType == kEntryBlock) {
4340 labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07004341 if (blockList[i]->firstMIRInsn == NULL) {
4342 continue;
4343 } else {
4344 setupLoopEntryBlock(cUnit, blockList[i],
4345 &labelList[blockList[i]->fallThrough->id]);
4346 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004347 } else if (blockList[i]->blockType == kExitBlock) {
4348 labelList[i].opCode = ARM_PSEUDO_kExitBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07004349 goto gen_fallthrough;
Bill Buzbee1465db52009-09-23 17:17:35 -07004350 } else if (blockList[i]->blockType == kDalvikByteCode) {
4351 labelList[i].opCode = kArmPseudoNormalBlockLabel;
Ben Chenge9695e52009-06-16 16:11:47 -07004352 /* Reset the register state */
Bill Buzbee1465db52009-09-23 17:17:35 -07004353 resetRegPool(cUnit);
4354 clobberAllRegs(cUnit);
4355 resetNullCheckTracker(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004356 } else {
4357 switch (blockList[i]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004358 case kChainingCellNormal:
4359 labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004360 /* handle the codegen later */
4361 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004362 &chainingListByType[kChainingCellNormal], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004363 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004364 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07004365 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004366 ARM_PSEUDO_kChainingCellInvokeSingleton;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004367 labelList[i].operands[0] =
4368 (int) blockList[i]->containingMethod;
4369 /* handle the codegen later */
4370 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004371 &chainingListByType[kChainingCellInvokeSingleton],
Ben Cheng38329f52009-07-07 14:19:20 -07004372 (void *) i);
4373 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004374 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07004375 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004376 ARM_PSEUDO_kChainingCellInvokePredicted;
Ben Cheng38329f52009-07-07 14:19:20 -07004377 /* handle the codegen later */
4378 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004379 &chainingListByType[kChainingCellInvokePredicted],
Ben Cheng38329f52009-07-07 14:19:20 -07004380 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004381 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004382 case kChainingCellHot:
Ben Chengba4fc8b2009-06-01 13:00:29 -07004383 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004384 ARM_PSEUDO_kChainingCellHot;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004385 /* handle the codegen later */
4386 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004387 &chainingListByType[kChainingCellHot],
Ben Chengba4fc8b2009-06-01 13:00:29 -07004388 (void *) i);
4389 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004390 case kPCReconstruction:
Ben Chengba4fc8b2009-06-01 13:00:29 -07004391 /* Make sure exception handling block is next */
4392 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004393 ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004394 assert (i == cUnit->numBlocks - 2);
4395 handlePCReconstruction(cUnit, &labelList[i+1]);
4396 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004397 case kExceptionHandling:
4398 labelList[i].opCode = kArmPseudoEHBlockLabel;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004399 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07004400 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4401 jitToInterpEntries.dvmJitToInterpPunt),
4402 r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07004403 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004404 }
4405 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004406#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07004407 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07004408 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004409 ARM_PSEUDO_kChainingCellBackwardBranch;
Jeff Hao97319a82009-08-12 16:57:15 -07004410 /* handle the codegen later */
4411 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004412 &chainingListByType[kChainingCellBackwardBranch],
Jeff Hao97319a82009-08-12 16:57:15 -07004413 (void *) i);
4414 break;
4415#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004416 default:
4417 break;
4418 }
4419 continue;
4420 }
Ben Chenge9695e52009-06-16 16:11:47 -07004421
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004422 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07004423
Ben Chengba4fc8b2009-06-01 13:00:29 -07004424 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004425
4426 resetRegPool(cUnit);
4427 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
4428 clobberAllRegs(cUnit);
4429 }
4430
4431 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
4432 resetDefTracking(cUnit);
4433 }
4434
4435 if (mir->dalvikInsn.opCode >= kMirOpFirst) {
Ben Cheng4238ec22009-08-24 16:32:22 -07004436 handleExtendedMIR(cUnit, mir);
4437 continue;
4438 }
4439
Bill Buzbee1465db52009-09-23 17:17:35 -07004440
Ben Chengba4fc8b2009-06-01 13:00:29 -07004441 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
4442 InstructionFormat dalvikFormat =
4443 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004444 ArmLIR *boundaryLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004445 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
Ben Chengccd6c012009-10-15 14:52:45 -07004446 mir->offset,
4447 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
4448 );
Ben Cheng4238ec22009-08-24 16:32:22 -07004449 if (mir->ssaRep) {
4450 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07004451 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07004452 }
4453
Ben Chenge9695e52009-06-16 16:11:47 -07004454 /* Remember the first LIR for this block */
4455 if (headLIR == NULL) {
4456 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07004457 /* Set the first boundaryLIR as a scheduling barrier */
4458 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07004459 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004460
Ben Chengba4fc8b2009-06-01 13:00:29 -07004461 bool notHandled;
4462 /*
4463 * Debugging: screen the opcode first to see if it is in the
4464 * do[-not]-compile list
4465 */
4466 bool singleStepMe =
4467 gDvmJit.includeSelectedOp !=
4468 ((gDvmJit.opList[dalvikOpCode >> 3] &
4469 (1 << (dalvikOpCode & 0x7))) !=
4470 0);
Jeff Hao97319a82009-08-12 16:57:15 -07004471#if defined(WITH_SELF_VERIFICATION)
4472 /* Punt on opcodes we can't replay */
4473 if (selfVerificationPuntOps(dalvikOpCode))
4474 singleStepMe = true;
4475#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004476 if (singleStepMe || cUnit->allSingleStep) {
4477 notHandled = false;
4478 genInterpSingleStep(cUnit, mir);
4479 } else {
4480 opcodeCoverage[dalvikOpCode]++;
4481 switch (dalvikFormat) {
4482 case kFmt10t:
4483 case kFmt20t:
4484 case kFmt30t:
4485 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4486 mir, blockList[i], labelList);
4487 break;
4488 case kFmt10x:
4489 notHandled = handleFmt10x(cUnit, mir);
4490 break;
4491 case kFmt11n:
4492 case kFmt31i:
4493 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4494 break;
4495 case kFmt11x:
4496 notHandled = handleFmt11x(cUnit, mir);
4497 break;
4498 case kFmt12x:
4499 notHandled = handleFmt12x(cUnit, mir);
4500 break;
4501 case kFmt20bc:
4502 notHandled = handleFmt20bc(cUnit, mir);
4503 break;
4504 case kFmt21c:
4505 case kFmt31c:
4506 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4507 break;
4508 case kFmt21h:
4509 notHandled = handleFmt21h(cUnit, mir);
4510 break;
4511 case kFmt21s:
4512 notHandled = handleFmt21s(cUnit, mir);
4513 break;
4514 case kFmt21t:
4515 notHandled = handleFmt21t(cUnit, mir, blockList[i],
4516 labelList);
4517 break;
4518 case kFmt22b:
4519 case kFmt22s:
4520 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4521 break;
4522 case kFmt22c:
4523 notHandled = handleFmt22c(cUnit, mir);
4524 break;
4525 case kFmt22cs:
4526 notHandled = handleFmt22cs(cUnit, mir);
4527 break;
4528 case kFmt22t:
4529 notHandled = handleFmt22t(cUnit, mir, blockList[i],
4530 labelList);
4531 break;
4532 case kFmt22x:
4533 case kFmt32x:
4534 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4535 break;
4536 case kFmt23x:
4537 notHandled = handleFmt23x(cUnit, mir);
4538 break;
4539 case kFmt31t:
4540 notHandled = handleFmt31t(cUnit, mir);
4541 break;
4542 case kFmt3rc:
4543 case kFmt35c:
4544 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4545 labelList);
4546 break;
4547 case kFmt3rms:
4548 case kFmt35ms:
4549 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4550 labelList);
4551 break;
4552 case kFmt3inline:
4553 notHandled = handleFmt3inline(cUnit, mir);
4554 break;
4555 case kFmt51l:
4556 notHandled = handleFmt51l(cUnit, mir);
4557 break;
4558 default:
4559 notHandled = true;
4560 break;
4561 }
4562 }
4563 if (notHandled) {
4564 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4565 mir->offset,
4566 dalvikOpCode, getOpcodeName(dalvikOpCode),
4567 dalvikFormat);
4568 dvmAbort();
4569 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004570 }
4571 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004572
Bill Buzbee1465db52009-09-23 17:17:35 -07004573 if (blockList[i]->blockType == kEntryBlock) {
Ben Cheng4238ec22009-08-24 16:32:22 -07004574 dvmCompilerAppendLIR(cUnit,
4575 (LIR *) cUnit->loopAnalysis->branchToBody);
4576 dvmCompilerAppendLIR(cUnit,
4577 (LIR *) cUnit->loopAnalysis->branchToPCR);
4578 }
4579
4580 if (headLIR) {
4581 /*
4582 * Eliminate redundant loads/stores and delay stores into later
4583 * slots
4584 */
4585 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4586 cUnit->lastLIRInsn);
4587 }
4588
4589gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004590 /*
4591 * Check if the block is terminated due to trace length constraint -
4592 * insert an unconditional branch to the chaining cell.
4593 */
4594 if (blockList[i]->needFallThroughBranch) {
4595 genUnconditionalBranch(cUnit,
4596 &labelList[blockList[i]->fallThrough->id]);
4597 }
4598
Ben Chengba4fc8b2009-06-01 13:00:29 -07004599 }
4600
Ben Chenge9695e52009-06-16 16:11:47 -07004601 /* Handle the chaining cells in predefined order */
Bill Buzbee1465db52009-09-23 17:17:35 -07004602 for (i = 0; i < kChainingCellLast; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004603 size_t j;
4604 int *blockIdList = (int *) chainingListByType[i].elemList;
4605
4606 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4607
4608 /* No chaining cells of this type */
4609 if (cUnit->numChainingCells[i] == 0)
4610 continue;
4611
4612 /* Record the first LIR for a new type of chaining cell */
4613 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4614
4615 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4616 int blockId = blockIdList[j];
4617
4618 /* Align this chaining cell first */
Bill Buzbee1465db52009-09-23 17:17:35 -07004619 newLIR0(cUnit, kArmPseudoPseudoAlign4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004620
4621 /* Insert the pseudo chaining instruction */
4622 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4623
4624
4625 switch (blockList[blockId]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004626 case kChainingCellNormal:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004627 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004628 blockList[blockId]->startOffset);
4629 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004630 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07004631 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004632 blockList[blockId]->containingMethod);
4633 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004634 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07004635 handleInvokePredictedChainingCell(cUnit);
4636 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004637 case kChainingCellHot:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004638 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004639 blockList[blockId]->startOffset);
4640 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004641#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07004642 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07004643 handleBackwardBranchChainingCell(cUnit,
4644 blockList[blockId]->startOffset);
4645 break;
4646#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004647 default:
Bill Buzbee1465db52009-09-23 17:17:35 -07004648 LOGE("Bad blocktype %d", blockList[blockId]->blockType);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004649 dvmAbort();
4650 break;
4651 }
4652 }
4653 }
Ben Chenge9695e52009-06-16 16:11:47 -07004654
Ben Cheng6c10a972009-10-29 14:39:18 -07004655 /*
4656 * Generate the branch to the dvmJitToInterpNoChain entry point at the end
4657 * of all chaining cells for the overflow cases.
4658 */
4659 if (cUnit->switchOverflowPad) {
4660 loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
4661 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4662 jitToInterpEntries.dvmJitToInterpNoChain), r2);
4663 opRegReg(cUnit, kOpAdd, r1, r1);
4664 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
4665#if defined(EXIT_STATS)
4666 loadConstant(cUnit, r0, kSwitchOverflow);
4667#endif
4668 opReg(cUnit, kOpBlx, r2);
4669 }
4670
Ben Chenge9695e52009-06-16 16:11:47 -07004671 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004672}
4673
4674/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004675bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004676{
Ben Chengccd6c012009-10-15 14:52:45 -07004677 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004678
Ben Chengccd6c012009-10-15 14:52:45 -07004679 if (gDvmJit.codeCacheFull) {
4680 return false;
4681 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07004682
Ben Chengccd6c012009-10-15 14:52:45 -07004683 switch (work->kind) {
4684 case kWorkOrderMethod:
4685 res = dvmCompileMethod(work->info, &work->result);
4686 break;
4687 case kWorkOrderTrace:
4688 /* Start compilation with maximally allowed trace length */
4689 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
4690 break;
4691 case kWorkOrderTraceDebug: {
4692 bool oldPrintMe = gDvmJit.printMe;
4693 gDvmJit.printMe = true;
4694 /* Start compilation with maximally allowed trace length */
4695 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
4696 gDvmJit.printMe = oldPrintMe;;
4697 break;
4698 }
4699 default:
4700 res = false;
4701 dvmAbort();
4702 }
4703 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004704}
4705
Ben Chengba4fc8b2009-06-01 13:00:29 -07004706/* Architectural-specific debugging helpers go here */
4707void dvmCompilerArchDump(void)
4708{
4709 /* Print compiled opcode in this VM instance */
4710 int i, start, streak;
4711 char buf[1024];
4712
4713 streak = i = 0;
4714 buf[0] = 0;
4715 while (opcodeCoverage[i] == 0 && i < 256) {
4716 i++;
4717 }
4718 if (i == 256) {
4719 return;
4720 }
4721 for (start = i++, streak = 1; i < 256; i++) {
4722 if (opcodeCoverage[i]) {
4723 streak++;
4724 } else {
4725 if (streak == 1) {
4726 sprintf(buf+strlen(buf), "%x,", start);
4727 } else {
4728 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4729 }
4730 streak = 0;
4731 while (opcodeCoverage[i] == 0 && i < 256) {
4732 i++;
4733 }
4734 if (i < 256) {
4735 streak = 1;
4736 start = i;
4737 }
4738 }
4739 }
4740 if (streak) {
4741 if (streak == 1) {
4742 sprintf(buf+strlen(buf), "%x", start);
4743 } else {
4744 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4745 }
4746 }
4747 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004748 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004749 }
4750}
Ben Chengd7d426a2009-09-22 11:23:36 -07004751
4752/* Common initialization routine for an architecture family */
4753bool dvmCompilerArchInit()
4754{
4755 int i;
4756
Bill Buzbee1465db52009-09-23 17:17:35 -07004757 for (i = 0; i < kArmLast; i++) {
Ben Chengd7d426a2009-09-22 11:23:36 -07004758 if (EncodingMap[i].opCode != i) {
4759 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4760 EncodingMap[i].name, i, EncodingMap[i].opCode);
4761 dvmAbort();
4762 }
4763 }
4764
4765 return compilerArchVariantInit();
4766}