blob: 9563df176dd8325c156b7a689e6a1e0b6d15a484 [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 Buzbee1465db52009-09-23 17:17:35 -07001443 loadValueDirectFixed(cUnit, rlSrc1, r0);
1444 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001445 loadConstant(cUnit, r2, (int)funct);
Bill Buzbee1465db52009-09-23 17:17:35 -07001446 opReg(cUnit, kOpBlx, r2);
1447 clobberCallRegs(cUnit);
1448 rlResult = getReturnLoc(cUnit);
1449 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001450 return false;
1451}
1452
Bill Buzbee1465db52009-09-23 17:17:35 -07001453bool handleArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1454 RegLocation rlDest, RegLocation rlSrc1,
1455 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001456{
Bill Buzbee1465db52009-09-23 17:17:35 -07001457 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001458 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001459
Ben Chengba4fc8b2009-06-01 13:00:29 -07001460 /* TODO: use a proper include file to define these */
1461 double __aeabi_dadd(double a, double b);
1462 double __aeabi_dsub(double a, double b);
1463 double __aeabi_ddiv(double a, double b);
1464 double __aeabi_dmul(double a, double b);
1465 double fmod(double a, double b);
1466
1467 switch (mir->dalvikInsn.opCode) {
1468 case OP_ADD_DOUBLE_2ADDR:
1469 case OP_ADD_DOUBLE:
1470 funct = (void*) __aeabi_dadd;
1471 break;
1472 case OP_SUB_DOUBLE_2ADDR:
1473 case OP_SUB_DOUBLE:
1474 funct = (void*) __aeabi_dsub;
1475 break;
1476 case OP_DIV_DOUBLE_2ADDR:
1477 case OP_DIV_DOUBLE:
1478 funct = (void*) __aeabi_ddiv;
1479 break;
1480 case OP_MUL_DOUBLE_2ADDR:
1481 case OP_MUL_DOUBLE:
1482 funct = (void*) __aeabi_dmul;
1483 break;
1484 case OP_REM_DOUBLE_2ADDR:
1485 case OP_REM_DOUBLE:
1486 funct = (void*) fmod;
1487 break;
1488 case OP_NEG_DOUBLE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001489 genNegDouble(cUnit, rlDest, rlSrc1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001490 return false;
1491 }
1492 default:
1493 return true;
1494 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001495 loadConstant(cUnit, rlr, (int)funct);
1496 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1497 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1498 opReg(cUnit, kOpBlx, rlr);
1499 clobberCallRegs(cUnit);
1500 rlResult = getReturnLocWide(cUnit);
1501 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001502 return false;
1503}
1504
Bill Buzbee1465db52009-09-23 17:17:35 -07001505static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir,
1506 RegLocation rlDest, RegLocation rlSrc1,
1507 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001508{
Bill Buzbee1465db52009-09-23 17:17:35 -07001509 RegLocation rlResult;
1510 OpKind firstOp = kOpBkpt;
1511 OpKind secondOp = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001512 bool callOut = false;
1513 void *callTgt;
1514 int retReg = r0;
1515 /* TODO - find proper .h file to declare these */
1516 long long __aeabi_ldivmod(long long op1, long long op2);
1517
1518 switch (mir->dalvikInsn.opCode) {
1519 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07001520 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1521 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1522 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1523 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1524 storeValueWide(cUnit, rlDest, rlResult);
1525 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001526 break;
1527 case OP_ADD_LONG:
1528 case OP_ADD_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001529 firstOp = kOpAdd;
1530 secondOp = kOpAdc;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001531 break;
1532 case OP_SUB_LONG:
1533 case OP_SUB_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001534 firstOp = kOpSub;
1535 secondOp = kOpSbc;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001536 break;
1537 case OP_MUL_LONG:
1538 case OP_MUL_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001539 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001540 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001541 case OP_DIV_LONG:
1542 case OP_DIV_LONG_2ADDR:
1543 callOut = true;
1544 retReg = r0;
1545 callTgt = (void*)__aeabi_ldivmod;
1546 break;
1547 /* NOTE - result is in r2/r3 instead of r0/r1 */
1548 case OP_REM_LONG:
1549 case OP_REM_LONG_2ADDR:
1550 callOut = true;
1551 callTgt = (void*)__aeabi_ldivmod;
1552 retReg = r2;
1553 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001554 case OP_AND_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001555 case OP_AND_LONG:
1556 firstOp = kOpAnd;
1557 secondOp = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001558 break;
1559 case OP_OR_LONG:
1560 case OP_OR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001561 firstOp = kOpOr;
1562 secondOp = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001563 break;
1564 case OP_XOR_LONG:
1565 case OP_XOR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001566 firstOp = kOpXor;
1567 secondOp = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001568 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001569 case OP_NEG_LONG: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001570 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1571 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1572 loadConstantValue(cUnit, rlResult.highReg, 0);
1573 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1574 rlResult.highReg, rlSrc2.lowReg);
1575 opRegReg(cUnit, kOpSbc, rlResult.highReg, rlSrc2.highReg);
1576 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001577 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001578 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001579 default:
1580 LOGE("Invalid long arith op");
1581 dvmAbort();
1582 }
1583 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001584 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001585 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001586 // Adjust return regs in to handle case of rem returning r2/r3
1587 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1588 loadConstant(cUnit, rlr, (int) callTgt);
1589 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1590 opReg(cUnit, kOpBlx, rlr);
1591 clobberCallRegs(cUnit);
1592 if (retReg == r0)
1593 rlResult = getReturnLocWide(cUnit);
1594 else
1595 rlResult = getReturnLocWideAlt(cUnit);
1596 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001597 }
1598 return false;
1599}
1600
Bill Buzbee1465db52009-09-23 17:17:35 -07001601static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir,
1602 RegLocation rlDest, RegLocation rlSrc1,
1603 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001604{
Bill Buzbee1465db52009-09-23 17:17:35 -07001605 OpKind op = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001606 bool callOut = false;
1607 bool checkZero = false;
Bill Buzbee1465db52009-09-23 17:17:35 -07001608 bool unary = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001609 int retReg = r0;
1610 void *callTgt;
Bill Buzbee1465db52009-09-23 17:17:35 -07001611 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001612
1613 /* TODO - find proper .h file to declare these */
1614 int __aeabi_idivmod(int op1, int op2);
1615 int __aeabi_idiv(int op1, int op2);
1616
1617 switch (mir->dalvikInsn.opCode) {
1618 case OP_NEG_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001619 op = kOpNeg;
1620 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001621 break;
1622 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001623 op = kOpMvn;
1624 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001625 break;
1626 case OP_ADD_INT:
1627 case OP_ADD_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001628 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001629 break;
1630 case OP_SUB_INT:
1631 case OP_SUB_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001632 op = kOpSub;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001633 break;
1634 case OP_MUL_INT:
1635 case OP_MUL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001636 op = kOpMul;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001637 break;
1638 case OP_DIV_INT:
1639 case OP_DIV_INT_2ADDR:
1640 callOut = true;
1641 checkZero = true;
1642 callTgt = __aeabi_idiv;
1643 retReg = r0;
1644 break;
1645 /* NOTE: returns in r1 */
1646 case OP_REM_INT:
1647 case OP_REM_INT_2ADDR:
1648 callOut = true;
1649 checkZero = true;
1650 callTgt = __aeabi_idivmod;
1651 retReg = r1;
1652 break;
1653 case OP_AND_INT:
1654 case OP_AND_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001655 op = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001656 break;
1657 case OP_OR_INT:
1658 case OP_OR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001659 op = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001660 break;
1661 case OP_XOR_INT:
1662 case OP_XOR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001663 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001664 break;
1665 case OP_SHL_INT:
1666 case OP_SHL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001667 op = kOpLsl;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001668 break;
1669 case OP_SHR_INT:
1670 case OP_SHR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001671 op = kOpAsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001672 break;
1673 case OP_USHR_INT:
1674 case OP_USHR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001675 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001676 break;
1677 default:
1678 LOGE("Invalid word arith op: 0x%x(%d)",
1679 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1680 dvmAbort();
1681 }
1682 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001683 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1684 if (unary) {
1685 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1686 opRegReg(cUnit, op, rlResult.lowReg,
1687 rlSrc1.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001688 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001689 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1690 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1691 opRegRegReg(cUnit, op, rlResult.lowReg,
1692 rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001693 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001694 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001695 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001696 RegLocation rlResult;
1697 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001698 loadConstant(cUnit, r2, (int) callTgt);
Bill Buzbee1465db52009-09-23 17:17:35 -07001699 loadValueDirectFixed(cUnit, rlSrc1, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001700 if (checkZero) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001701 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001702 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001703 opReg(cUnit, kOpBlx, r2);
1704 clobberCallRegs(cUnit);
1705 if (retReg == r0)
1706 rlResult = getReturnLoc(cUnit);
1707 else
1708 rlResult = getReturnLocAlt(cUnit);
1709 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001710 }
1711 return false;
1712}
1713
Bill Buzbee1465db52009-09-23 17:17:35 -07001714static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001715{
1716 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001717 RegLocation rlDest;
1718 RegLocation rlSrc1;
1719 RegLocation rlSrc2;
1720 /* Deduce sizes of operands */
1721 if (mir->ssaRep->numUses == 2) {
1722 rlSrc1 = getSrcLoc(cUnit, mir, 0);
1723 rlSrc2 = getSrcLoc(cUnit, mir, 1);
1724 } else if (mir->ssaRep->numUses == 3) {
1725 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1726 rlSrc2 = getSrcLoc(cUnit, mir, 2);
1727 } else {
1728 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1729 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
1730 assert(mir->ssaRep->numUses == 4);
1731 }
1732 if (mir->ssaRep->numDefs == 1) {
1733 rlDest = getDestLoc(cUnit, mir, 0);
1734 } else {
1735 assert(mir->ssaRep->numDefs == 2);
1736 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1737 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001738
1739 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001740 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001741 }
1742 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001743 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001744 }
1745 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001746 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001747 }
1748 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001749 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001750 }
1751 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001752 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001753 }
1754 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001755 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001756 }
1757 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001758 return handleArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001759 }
1760 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001761 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001762 }
1763 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001764 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001765 }
1766 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001767 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001768 }
1769 return true;
1770}
1771
Bill Buzbee1465db52009-09-23 17:17:35 -07001772/* Generate conditional branch instructions */
1773static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1774 ArmConditionCode cond,
1775 ArmLIR *target)
1776{
1777 ArmLIR *branch = opCondBranch(cUnit, cond);
1778 branch->generic.target = (LIR *) target;
1779 return branch;
1780}
1781
1782/* Generate unconditional branch instructions */
1783static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1784{
1785 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
1786 branch->generic.target = (LIR *) target;
1787 return branch;
1788}
1789
1790/*
1791 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
1792 * blocks.
1793 */
1794static void genBarrier(CompilationUnit *cUnit)
1795{
1796 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
1797 /* Mark all resources as being clobbered */
1798 barrier->defMask = -1;
1799}
1800
1801/* Perform the actual operation for OP_RETURN_* */
1802static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
1803{
1804 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
1805#if defined(INVOKE_STATS)
1806 gDvmJit.returnOp++;
1807#endif
1808 int dPC = (int) (cUnit->method->insns + mir->offset);
1809 /* Insert branch, but defer setting of target */
1810 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
1811 /* Set up the place holder to reconstruct this Dalvik PC */
1812 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1813 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
1814 pcrLabel->operands[0] = dPC;
1815 pcrLabel->operands[1] = mir->offset;
1816 /* Insert the place holder to the growable list */
1817 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1818 /* Branch to the PC reconstruction code */
1819 branch->generic.target = (LIR *) pcrLabel;
1820}
1821
Bill Buzbeed45ba372009-06-15 17:00:57 -07001822static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1823 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001824{
Ben Chenge9695e52009-06-16 16:11:47 -07001825 /*
1826 * Don't optimize the register usage since it calls out to template
1827 * functions
1828 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001829 RegLocation rlSrc;
1830 RegLocation rlDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001831 if (srcSize == 1) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001832 rlSrc = getSrcLoc(cUnit, mir, 0);
1833 loadValueDirectFixed(cUnit, rlSrc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001834 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001835 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1836 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001837 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001838 loadConstant(cUnit, r2, (int)funct);
1839 opReg(cUnit, kOpBlx, r2);
1840 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001841 if (tgtSize == 1) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001842 RegLocation rlResult;
1843 rlDest = getDestLoc(cUnit, mir, 0);
1844 rlResult = getReturnLoc(cUnit);
1845 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001846 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001847 RegLocation rlResult;
1848 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1849 rlResult = getReturnLocWide(cUnit);
1850 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001851 }
1852 return false;
1853}
1854
Ben Chengba4fc8b2009-06-01 13:00:29 -07001855static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1856 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001857 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001858{
1859 unsigned int i;
1860 unsigned int regMask = 0;
Bill Buzbee1465db52009-09-23 17:17:35 -07001861 RegLocation rlArg;
1862 int numDone = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001863
Bill Buzbee1465db52009-09-23 17:17:35 -07001864 /*
1865 * Load arguments to r0..r4. Note that these registers may contain
1866 * live values, so we clobber them immediately after loading to prevent
1867 * them from being used as sources for subsequent loads.
1868 */
1869 lockAllTemps(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001870 for (i = 0; i < dInsn->vA; i++) {
1871 regMask |= 1 << i;
Bill Buzbee1465db52009-09-23 17:17:35 -07001872 rlArg = getSrcLoc(cUnit, mir, numDone++);
1873 loadValueDirectFixed(cUnit, rlArg, i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001874 }
1875 if (regMask) {
1876 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee1465db52009-09-23 17:17:35 -07001877 opRegRegImm(cUnit, kOpSub, r7, rFP,
1878 sizeof(StackSaveArea) + (dInsn->vA << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001879 /* generate null check */
1880 if (pcrLabel) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001881 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1882 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001883 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001884 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001885 }
1886}
1887
1888static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1889 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001890 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001891{
1892 int srcOffset = dInsn->vC << 2;
1893 int numArgs = dInsn->vA;
1894 int regMask;
Bill Buzbee1465db52009-09-23 17:17:35 -07001895
1896 /*
1897 * Note: here, all promoted registers will have been flushed
1898 * back to the Dalvik base locations, so register usage restrictins
1899 * are lifted. All parms loaded from original Dalvik register
1900 * region - even though some might conceivably have valid copies
1901 * cached in a preserved register.
1902 */
1903 lockAllTemps(cUnit);
1904
Ben Chengba4fc8b2009-06-01 13:00:29 -07001905 /*
1906 * r4PC : &rFP[vC]
1907 * r7: &newFP[0]
1908 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001909 opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001910 /* load [r0 .. min(numArgs,4)] */
1911 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001912 /*
1913 * Protect the loadMultiple instruction from being reordered with other
1914 * Dalvik stack accesses.
1915 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001916 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001917
Bill Buzbee1465db52009-09-23 17:17:35 -07001918 opRegRegImm(cUnit, kOpSub, r7, rFP,
1919 sizeof(StackSaveArea) + (numArgs << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001920 /* generate null check */
1921 if (pcrLabel) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001922 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1923 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001924 }
1925
1926 /*
1927 * Handle remaining 4n arguments:
1928 * store previously loaded 4 values and load the next 4 values
1929 */
1930 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001931 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001932 /*
1933 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001934 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001935 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001936 opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001937 /* No need to generate the loop structure if numArgs <= 11 */
1938 if (numArgs > 11) {
1939 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee1465db52009-09-23 17:17:35 -07001940 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07001941 loopLabel->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001942 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001943 storeMultiple(cUnit, r7, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001944 /*
1945 * Protect the loadMultiple instruction from being reordered with other
1946 * Dalvik stack accesses.
1947 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001948 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001949 /* No need to generate the loop structure if numArgs <= 11 */
1950 if (numArgs > 11) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001951 opRegImm(cUnit, kOpSub, rFP, 4);
1952 genConditionalBranch(cUnit, kArmCondNe, loopLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001953 }
1954 }
1955
1956 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001957 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001958
1959 /* Generate the loop epilogue - don't use r0 */
1960 if ((numArgs > 4) && (numArgs % 4)) {
1961 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001962 /*
1963 * Protect the loadMultiple instruction from being reordered with other
1964 * Dalvik stack accesses.
1965 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001966 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001967 }
1968 if (numArgs >= 8)
Bill Buzbee1465db52009-09-23 17:17:35 -07001969 opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001970
1971 /* Save the modulo 4 arguments */
1972 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001973 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001974 }
1975}
1976
Ben Cheng38329f52009-07-07 14:19:20 -07001977/*
1978 * Generate code to setup the call stack then jump to the chaining cell if it
1979 * is not a native method.
1980 */
1981static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001982 BasicBlock *bb, ArmLIR *labelList,
1983 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001984 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001985{
Bill Buzbee1465db52009-09-23 17:17:35 -07001986 /*
1987 * Note: all Dalvik register state should be flushed to
1988 * memory by the point, so register usage restrictions no
1989 * longer apply. All temp & preserved registers may be used.
1990 */
1991 lockAllTemps(cUnit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001992 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001993
1994 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07001995 lockTemp(cUnit, r1);
1996 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001997 /* r4PC = dalvikCallsite */
1998 loadConstant(cUnit, r4PC,
1999 (int) (cUnit->method->insns + mir->offset));
2000 addrRetChain->generic.target = (LIR *) retChainingCell;
2001 /*
Ben Cheng38329f52009-07-07 14:19:20 -07002002 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002003 * r1 = &ChainingCell
2004 * r4PC = callsiteDPC
2005 */
2006 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07002007 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002008#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07002009 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002010#endif
2011 } else {
2012 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
2013#if defined(INVOKE_STATS)
2014 gDvmJit.invokeChain++;
2015#endif
Ben Cheng38329f52009-07-07 14:19:20 -07002016 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002017 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2018 }
2019 /* Handle exceptions using the interpreter */
2020 genTrap(cUnit, mir->offset, pcrLabel);
2021}
2022
Ben Cheng38329f52009-07-07 14:19:20 -07002023/*
2024 * Generate code to check the validity of a predicted chain and take actions
2025 * based on the result.
2026 *
2027 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
2028 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
2029 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
2030 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
2031 * 0x426a99b2 : blx_2 see above --+
2032 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
2033 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
2034 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
2035 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
2036 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
2037 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
2038 * 0x426a99c0 : blx r7 --+
2039 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
2040 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2041 * 0x426a99c6 : blx_2 see above --+
2042 */
2043static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
2044 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002045 ArmLIR *retChainingCell,
2046 ArmLIR *predChainingCell,
2047 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07002048{
Bill Buzbee1465db52009-09-23 17:17:35 -07002049 /*
2050 * Note: all Dalvik register state should be flushed to
2051 * memory by the point, so register usage restrictions no
2052 * longer apply. Lock temps to prevent them from being
2053 * allocated by utility routines.
2054 */
2055 lockAllTemps(cUnit);
2056
Ben Cheng38329f52009-07-07 14:19:20 -07002057 /* "this" is already left in r0 by genProcessArgs* */
2058
2059 /* r4PC = dalvikCallsite */
2060 loadConstant(cUnit, r4PC,
2061 (int) (cUnit->method->insns + mir->offset));
2062
2063 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002064 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002065 addrRetChain->generic.target = (LIR *) retChainingCell;
2066
2067 /* r2 = &predictedChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002068 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002069 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2070
2071 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2072
2073 /* return through lr - jump to the chaining cell */
2074 genUnconditionalBranch(cUnit, predChainingCell);
2075
2076 /*
2077 * null-check on "this" may have been eliminated, but we still need a PC-
2078 * reconstruction label for stack overflow bailout.
2079 */
2080 if (pcrLabel == NULL) {
2081 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002082 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07002083 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07002084 pcrLabel->operands[0] = dPC;
2085 pcrLabel->operands[1] = mir->offset;
2086 /* Insert the place holder to the growable list */
2087 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2088 }
2089
2090 /* return through lr+2 - punt to the interpreter */
2091 genUnconditionalBranch(cUnit, pcrLabel);
2092
2093 /*
2094 * return through lr+4 - fully resolve the callee method.
2095 * r1 <- count
2096 * r2 <- &predictedChainCell
2097 * r3 <- this->class
2098 * r4 <- dPC
2099 * r7 <- this->class->vtable
2100 */
2101
2102 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002103 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07002104
2105 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07002106 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002107
Bill Buzbee1465db52009-09-23 17:17:35 -07002108 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07002109
Bill Buzbee270c1d62009-08-13 16:58:07 -07002110 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2111 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002112
2113 /*
2114 * r0 = calleeMethod
2115 * r2 = &predictedChainingCell
2116 * r3 = class
2117 *
2118 * &returnChainingCell has been loaded into r1 but is not needed
2119 * when patching the chaining cell and will be clobbered upon
2120 * returning so it will be reconstructed again.
2121 */
Bill Buzbee1465db52009-09-23 17:17:35 -07002122 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002123
2124 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002125 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002126 addrRetChain->generic.target = (LIR *) retChainingCell;
2127
2128 bypassRechaining->generic.target = (LIR *) addrRetChain;
2129 /*
2130 * r0 = calleeMethod,
2131 * r1 = &ChainingCell,
2132 * r4PC = callsiteDPC,
2133 */
2134 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2135#if defined(INVOKE_STATS)
2136 gDvmJit.invokePredictedChain++;
2137#endif
2138 /* Handle exceptions using the interpreter */
2139 genTrap(cUnit, mir->offset, pcrLabel);
2140}
2141
2142/*
2143 * Up calling this function, "this" is stored in r0. The actual class will be
2144 * chased down off r0 and the predicted one will be retrieved through
2145 * predictedChainingCell then a comparison is performed to see whether the
2146 * previously established chaining is still valid.
2147 *
2148 * The return LIR is a branch based on the comparison result. The actual branch
2149 * target will be setup in the caller.
2150 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002151static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
2152 ArmLIR *predChainingCell,
2153 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07002154 MIR *mir)
2155{
Bill Buzbee1465db52009-09-23 17:17:35 -07002156 /*
2157 * Note: all Dalvik register state should be flushed to
2158 * memory by the point, so register usage restrictions no
2159 * longer apply. All temp & preserved registers may be used.
2160 */
2161 lockAllTemps(cUnit);
2162
Ben Cheng38329f52009-07-07 14:19:20 -07002163 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002164 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002165
2166 /*
2167 * r2 now contains predicted class. The starting offset of the
2168 * cached value is 4 bytes into the chaining cell.
2169 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002170 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002171 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07002172 getPredictedClass->generic.target = (LIR *) predChainingCell;
2173
2174 /*
2175 * r0 now contains predicted method. The starting offset of the
2176 * cached value is 8 bytes into the chaining cell.
2177 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002178 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002179 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07002180 getPredictedMethod->generic.target = (LIR *) predChainingCell;
2181
2182 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002183 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002184 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002185 getRechainingRequestCount->generic.target =
2186 (LIR *) predChainingCell;
2187
2188 /* r4PC = dalvikCallsite */
2189 loadConstant(cUnit, r4PC,
2190 (int) (cUnit->method->insns + mir->offset));
2191
2192 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002193 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002194 addrRetChain->generic.target = (LIR *) retChainingCell;
2195
2196 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee1465db52009-09-23 17:17:35 -07002197 opRegReg(cUnit, kOpCmp, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002198
Bill Buzbee1465db52009-09-23 17:17:35 -07002199 return opCondBranch(cUnit, kArmCondEq);
Ben Cheng38329f52009-07-07 14:19:20 -07002200}
2201
Ben Chengba4fc8b2009-06-01 13:00:29 -07002202/* Geneate a branch to go back to the interpreter */
2203static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
2204{
2205 /* r0 = dalvik pc */
Bill Buzbee1465db52009-09-23 17:17:35 -07002206 flushAllRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002207 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002208 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
2209 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2210 jitToInterpEntries.dvmJitToInterpPunt), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002211 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002212}
2213
2214/*
2215 * Attempt to single step one instruction using the interpreter and return
2216 * to the compiled code for the next Dalvik instruction
2217 */
2218static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
2219{
2220 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
2221 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
2222 kInstrCanThrow;
Bill Buzbee1465db52009-09-23 17:17:35 -07002223
2224 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
2225 flushAllRegs(cUnit);
2226
Ben Chengba4fc8b2009-06-01 13:00:29 -07002227 if ((mir->next == NULL) || (flags & flagsToCheck)) {
2228 genPuntToInterp(cUnit, mir->offset);
2229 return;
2230 }
2231 int entryAddr = offsetof(InterpState,
2232 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002233 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002234 /* r0 = dalvik pc */
2235 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
2236 /* r1 = dalvik pc of following instruction */
2237 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -07002238 opReg(cUnit, kOpBlx, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002239}
2240
Bill Buzbee1465db52009-09-23 17:17:35 -07002241static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002242{
Bill Buzbee1465db52009-09-23 17:17:35 -07002243 genExportPC(cUnit, mir);
2244 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2245 loadValueDirectFixed(cUnit, rlSrc, r1);
2246 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
2247 if (mir->dalvikInsn.opCode == OP_MONITOR_ENTER) {
2248 loadConstant(cUnit, r2, (int)dvmLockObject);
2249 } else {
2250 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2251 }
2252 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
2253 /* Do the call */
2254 opReg(cUnit, kOpBlx, r2);
2255 clobberCallRegs(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002256}
2257
2258/* Load a word at base + displacement. Displacement must be word multiple */
2259static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
2260 int rDest)
2261{
Bill Buzbee1465db52009-09-23 17:17:35 -07002262 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, false,
2263 INVALID_SREG);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002264}
2265
2266static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
Bill Buzbee1465db52009-09-23 17:17:35 -07002267 int displacement, int rSrc)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002268{
Bill Buzbee1465db52009-09-23 17:17:35 -07002269 return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002270}
2271
2272static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
2273{
2274 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
2275 dvmCompilerAppendLIR(cUnit, (LIR*)res);
2276 return res;
2277}
2278
Ben Chengba4fc8b2009-06-01 13:00:29 -07002279/*
2280 * The following are the first-level codegen routines that analyze the format
2281 * of each bytecode then either dispatch special purpose codegen routines
2282 * or produce corresponding Thumb instructions directly.
2283 */
2284
2285static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002286 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002287{
2288 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2289 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2290 return false;
2291}
2292
2293static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
2294{
2295 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2296 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
2297 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
2298 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2299 return true;
2300 }
2301 switch (dalvikOpCode) {
2302 case OP_RETURN_VOID:
2303 genReturnCommon(cUnit,mir);
2304 break;
2305 case OP_UNUSED_73:
2306 case OP_UNUSED_79:
2307 case OP_UNUSED_7A:
2308 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2309 return true;
2310 case OP_NOP:
2311 break;
2312 default:
2313 return true;
2314 }
2315 return false;
2316}
2317
2318static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2319{
Bill Buzbee1465db52009-09-23 17:17:35 -07002320 RegLocation rlDest;
2321 RegLocation rlResult;
2322 if (mir->ssaRep->numDefs == 2) {
2323 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2324 } else {
2325 rlDest = getDestLoc(cUnit, mir, 0);
2326 }
Ben Chenge9695e52009-06-16 16:11:47 -07002327
Ben Chengba4fc8b2009-06-01 13:00:29 -07002328 switch (mir->dalvikInsn.opCode) {
2329 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07002330 case OP_CONST_4: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002331 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2332 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2333 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002334 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002335 }
2336 case OP_CONST_WIDE_32: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002337 //TUNING: single routine to load constant pair for support doubles
2338 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2339 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2340 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2341 rlResult.lowReg, 31);
2342 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002343 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002344 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002345 default:
2346 return true;
2347 }
2348 return false;
2349}
2350
2351static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2352{
Bill Buzbee1465db52009-09-23 17:17:35 -07002353 RegLocation rlDest;
2354 RegLocation rlResult;
2355 if (mir->ssaRep->numDefs == 2) {
2356 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2357 } else {
2358 rlDest = getDestLoc(cUnit, mir, 0);
2359 }
2360 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Ben Chenge9695e52009-06-16 16:11:47 -07002361
Ben Chengba4fc8b2009-06-01 13:00:29 -07002362 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07002363 case OP_CONST_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002364 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
2365 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002366 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002367 }
2368 case OP_CONST_WIDE_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002369 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
2370 0, mir->dalvikInsn.vB << 16);
2371 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002372 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002373 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002374 default:
2375 return true;
2376 }
2377 return false;
2378}
2379
2380static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2381{
2382 /* For OP_THROW_VERIFICATION_ERROR */
2383 genInterpSingleStep(cUnit, mir);
2384 return false;
2385}
2386
2387static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2388{
Bill Buzbee1465db52009-09-23 17:17:35 -07002389 RegLocation rlResult;
2390 RegLocation rlDest;
2391 RegLocation rlSrc;
Ben Chenge9695e52009-06-16 16:11:47 -07002392
Ben Chengba4fc8b2009-06-01 13:00:29 -07002393 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002394 case OP_CONST_STRING_JUMBO:
2395 case OP_CONST_STRING: {
2396 void *strPtr = (void*)
2397 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2398 assert(strPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002399 rlDest = getDestLoc(cUnit, mir, 0);
2400 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2401 loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
2402 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002403 break;
2404 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002405 case OP_CONST_CLASS: {
2406 void *classPtr = (void*)
2407 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2408 assert(classPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002409 rlDest = getDestLoc(cUnit, mir, 0);
2410 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2411 loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
2412 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002413 break;
2414 }
2415 case OP_SGET_OBJECT:
2416 case OP_SGET_BOOLEAN:
2417 case OP_SGET_CHAR:
2418 case OP_SGET_BYTE:
2419 case OP_SGET_SHORT:
2420 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002421 int valOffset = offsetof(StaticField, value);
Bill Buzbee1465db52009-09-23 17:17:35 -07002422 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002423 void *fieldPtr = (void*)
2424 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2425 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002426 rlDest = getDestLoc(cUnit, mir, 0);
2427 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2428 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002429#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002430 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002431#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002432 int regMap = rlResult.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002433 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2434
Jeff Hao97319a82009-08-12 16:57:15 -07002435#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002436 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002437 break;
2438 }
2439 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002440 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002441 void *fieldPtr = (void*)
2442 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Bill Buzbee1465db52009-09-23 17:17:35 -07002443 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002444 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002445 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2446 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2447 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002448#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002449 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002450#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002451 int regMap = rlResult.highReg << 16 |
2452 rlResult.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002453 selfVerificationMemOpWrapper(cUnit, regMap,
2454 &selfVerificationLoadDoubleword);
2455
Jeff Hao97319a82009-08-12 16:57:15 -07002456#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002457 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002458 break;
2459 }
2460 case OP_SPUT_OBJECT:
2461 case OP_SPUT_BOOLEAN:
2462 case OP_SPUT_CHAR:
2463 case OP_SPUT_BYTE:
2464 case OP_SPUT_SHORT:
2465 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002466 int valOffset = offsetof(StaticField, value);
Bill Buzbee1465db52009-09-23 17:17:35 -07002467 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002468 void *fieldPtr = (void*)
2469 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002470
Ben Chengba4fc8b2009-06-01 13:00:29 -07002471 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002472 rlSrc = getSrcLoc(cUnit, mir, 0);
2473 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
2474 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002475#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002476 storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002477#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002478 int regMap = rlSrc.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002479 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2480#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002481 break;
2482 }
2483 case OP_SPUT_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002484 int tReg = allocTemp(cUnit);
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002485 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002486 void *fieldPtr = (void*)
2487 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002488
Ben Chengba4fc8b2009-06-01 13:00:29 -07002489 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002490 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2491 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
2492 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002493#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002494 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002495#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002496 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002497 selfVerificationMemOpWrapper(cUnit, regMap,
2498 &selfVerificationStoreDoubleword);
2499#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002500 break;
2501 }
2502 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002503 /*
2504 * Obey the calling convention and don't mess with the register
2505 * usage.
2506 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002507 ClassObject *classPtr = (void*)
2508 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2509 assert(classPtr != NULL);
2510 assert(classPtr->status & CLASS_INITIALIZED);
Ben Cheng79d173c2009-09-29 16:12:51 -07002511 /*
2512 * If it is going to throw, it should not make to the trace to begin
Bill Buzbee1465db52009-09-23 17:17:35 -07002513 * with. However, Alloc might throw, so we need to genExportPC()
Ben Cheng79d173c2009-09-29 16:12:51 -07002514 */
2515 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
Bill Buzbee1465db52009-09-23 17:17:35 -07002516 genExportPC(cUnit, mir);
2517 loadConstant(cUnit, r2, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002518 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002519 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07002520 opReg(cUnit, kOpBlx, r2);
2521 clobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07002522 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07002523 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2524 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07002525 /*
2526 * OOM exception needs to be thrown here and cannot re-execute
2527 */
2528 loadConstant(cUnit, r0,
2529 (int) (cUnit->method->insns + mir->offset));
2530 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2531 /* noreturn */
2532
Bill Buzbee1465db52009-09-23 17:17:35 -07002533 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07002534 target->defMask = ENCODE_ALL;
2535 branchOver->generic.target = (LIR *) target;
Bill Buzbee1465db52009-09-23 17:17:35 -07002536 rlDest = getDestLoc(cUnit, mir, 0);
2537 rlResult = getReturnLoc(cUnit);
2538 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002539 break;
2540 }
2541 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002542 /*
2543 * Obey the calling convention and don't mess with the register
2544 * usage.
2545 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002546 ClassObject *classPtr =
2547 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2548 loadConstant(cUnit, r1, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07002549 rlSrc = getSrcLoc(cUnit, mir, 0);
2550 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2551 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); /* Null? */
2552 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
2553 /*
2554 * rlSrc.lowReg now contains object->clazz. Note that
2555 * it could have been allocated r0, but we're okay so long
2556 * as we don't do anything desctructive until r0 is loaded
2557 * with clazz.
2558 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002559 /* r0 now contains object->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07002560 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
2561 loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
2562 opRegReg(cUnit, kOpCmp, r0, r1);
2563 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2564 opReg(cUnit, kOpBlx, r2);
2565 clobberCallRegs(cUnit);
2566 /*
2567 * If null, check cast failed - punt to the interpreter. Because
2568 * interpreter will be the one throwing, we don't need to
2569 * genExportPC() here.
2570 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002571 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002572 /* check cast passed - branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07002573 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07002574 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002575 branch1->generic.target = (LIR *)target;
2576 branch2->generic.target = (LIR *)target;
2577 break;
2578 }
2579 default:
2580 return true;
2581 }
2582 return false;
2583}
2584
2585static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2586{
2587 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002588 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002589 switch (dalvikOpCode) {
2590 case OP_MOVE_EXCEPTION: {
2591 int offset = offsetof(InterpState, self);
2592 int exOffset = offsetof(Thread, exception);
Bill Buzbee1465db52009-09-23 17:17:35 -07002593 int selfReg = allocTemp(cUnit);
2594 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2595 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2596 loadWordDisp(cUnit, rGLUE, offset, selfReg);
2597 loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
2598 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002599 break;
2600 }
2601 case OP_MOVE_RESULT:
2602 case OP_MOVE_RESULT_OBJECT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002603 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2604 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
2605 rlSrc.fp = rlDest.fp;
2606 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002607 break;
2608 }
2609 case OP_MOVE_RESULT_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002610 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
2611 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
2612 rlSrc.fp = rlDest.fp;
2613 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002614 break;
2615 }
2616 case OP_RETURN_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002617 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2618 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
2619 rlDest.fp = rlSrc.fp;
2620 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002621 genReturnCommon(cUnit,mir);
2622 break;
2623 }
2624 case OP_RETURN:
2625 case OP_RETURN_OBJECT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002626 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2627 RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
2628 rlDest.fp = rlSrc.fp;
2629 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002630 genReturnCommon(cUnit,mir);
2631 break;
2632 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002633 case OP_MONITOR_EXIT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002634 case OP_MONITOR_ENTER:
Bill Buzbee1465db52009-09-23 17:17:35 -07002635#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
2636 handleMonitorPortable(cUnit, mir);
2637#else
2638 handleMonitor(cUnit, mir);
2639#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002640 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002641 case OP_THROW: {
2642 genInterpSingleStep(cUnit, mir);
2643 break;
2644 }
2645 default:
2646 return true;
2647 }
2648 return false;
2649}
2650
Bill Buzbee1465db52009-09-23 17:17:35 -07002651static bool handleConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002652{
2653 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002654
Ben Chengba4fc8b2009-06-01 13:00:29 -07002655 float __aeabi_i2f( int op1 );
2656 int __aeabi_f2iz( float op1 );
2657 float __aeabi_d2f( double op1 );
2658 double __aeabi_f2d( float op1 );
2659 double __aeabi_i2d( int op1 );
2660 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002661 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002662 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002663 s8 dvmJitf2l( float op1 );
2664 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002665
Bill Buzbeed45ba372009-06-15 17:00:57 -07002666 switch (opCode) {
2667 case OP_INT_TO_FLOAT:
2668 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2669 case OP_FLOAT_TO_INT:
2670 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2671 case OP_DOUBLE_TO_FLOAT:
2672 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2673 case OP_FLOAT_TO_DOUBLE:
2674 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2675 case OP_INT_TO_DOUBLE:
2676 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2677 case OP_DOUBLE_TO_INT:
2678 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2679 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002680 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002681 case OP_LONG_TO_FLOAT:
2682 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2683 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002684 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002685 case OP_LONG_TO_DOUBLE:
2686 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2687 default:
2688 return true;
2689 }
2690 return false;
2691}
2692
2693static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2694{
2695 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002696 RegLocation rlDest;
2697 RegLocation rlSrc;
2698 RegLocation rlResult;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002699
Ben Chengba4fc8b2009-06-01 13:00:29 -07002700 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002701 return handleArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002702 }
2703
Bill Buzbee1465db52009-09-23 17:17:35 -07002704 if (mir->ssaRep->numUses == 2)
2705 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2706 else
2707 rlSrc = getSrcLoc(cUnit, mir, 0);
2708 if (mir->ssaRep->numDefs == 2)
2709 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2710 else
2711 rlDest = getDestLoc(cUnit, mir, 0);
Ben Chenge9695e52009-06-16 16:11:47 -07002712
Ben Chengba4fc8b2009-06-01 13:00:29 -07002713 switch (opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002714 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002715 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002716 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002717 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002718 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002719 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002720 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002721 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002722 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002723 case OP_LONG_TO_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002724 return handleConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002725 case OP_NEG_INT:
2726 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002727 return handleArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002728 case OP_NEG_LONG:
2729 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07002730 return handleArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002731 case OP_NEG_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002732 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002733 case OP_NEG_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002734 return handleArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
2735 case OP_MOVE_WIDE:
2736 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002737 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07002738 case OP_INT_TO_LONG:
2739 rlSrc = updateLoc(cUnit, rlSrc);
2740 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2741 if (rlSrc.location == kLocPhysReg) {
2742 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2743 } else {
2744 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
2745 }
2746 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2747 rlResult.lowReg, 31);
2748 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002749 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07002750 case OP_LONG_TO_INT:
2751 rlSrc = updateLocWide(cUnit, rlSrc);
2752 rlSrc = wideToNarrowLoc(cUnit, rlSrc);
2753 // Intentional fallthrough
Ben Chengba4fc8b2009-06-01 13:00:29 -07002754 case OP_MOVE:
2755 case OP_MOVE_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002756 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002757 break;
2758 case OP_INT_TO_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002759 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2760 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2761 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
2762 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002763 break;
2764 case OP_INT_TO_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002765 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2766 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2767 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
2768 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002769 break;
2770 case OP_INT_TO_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002771 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2772 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2773 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
2774 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002775 break;
2776 case OP_ARRAY_LENGTH: {
2777 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07002778 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2779 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
2780 mir->offset, NULL);
2781 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2782 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
2783 rlResult.lowReg);
2784 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002785 break;
2786 }
2787 default:
2788 return true;
2789 }
2790 return false;
2791}
2792
2793static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2794{
2795 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002796 RegLocation rlDest;
2797 RegLocation rlResult;
2798 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002799 if (dalvikOpCode == OP_CONST_WIDE_16) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002800 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2801 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2802 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
2803 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
2804 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002805 } else if (dalvikOpCode == OP_CONST_16) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002806 rlDest = getDestLoc(cUnit, mir, 0);
2807 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2808 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
2809 storeValue(cUnit, rlDest, rlResult);
2810 } else
Ben Chengba4fc8b2009-06-01 13:00:29 -07002811 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002812 return false;
2813}
2814
2815/* Compare agaist zero */
2816static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002817 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002818{
2819 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002820 ArmConditionCode cond;
Bill Buzbee1465db52009-09-23 17:17:35 -07002821 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2822 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2823 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002824
Bill Buzbee270c1d62009-08-13 16:58:07 -07002825//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002826 switch (dalvikOpCode) {
2827 case OP_IF_EQZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002828 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002829 break;
2830 case OP_IF_NEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002831 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002832 break;
2833 case OP_IF_LTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002834 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002835 break;
2836 case OP_IF_GEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002837 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002838 break;
2839 case OP_IF_GTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002840 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002841 break;
2842 case OP_IF_LEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002843 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002844 break;
2845 default:
2846 cond = 0;
2847 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2848 dvmAbort();
2849 }
2850 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2851 /* This mostly likely will be optimized away in a later phase */
2852 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2853 return false;
2854}
2855
2856static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2857{
2858 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002859 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2860 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2861 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002862 int lit = mir->dalvikInsn.vC;
Ben Cheng4f489172009-09-27 17:08:35 -07002863 OpKind op = 0; /* Make gcc happy */
Bill Buzbee1465db52009-09-23 17:17:35 -07002864 int shiftOp = false;
2865 bool isDiv = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002866
Ben Chengba4fc8b2009-06-01 13:00:29 -07002867 int __aeabi_idivmod(int op1, int op2);
2868 int __aeabi_idiv(int op1, int op2);
2869
2870 switch (dalvikOpCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002871 case OP_RSUB_INT_LIT8:
2872 case OP_RSUB_INT: {
2873 int tReg;
2874 //TUNING: add support for use of Arm rsub op
2875 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2876 tReg = allocTemp(cUnit);
2877 loadConstant(cUnit, tReg, lit);
2878 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2879 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
2880 tReg, rlSrc.lowReg);
2881 storeValue(cUnit, rlDest, rlResult);
2882 return false;
2883 break;
2884 }
2885
Ben Chengba4fc8b2009-06-01 13:00:29 -07002886 case OP_ADD_INT_LIT8:
2887 case OP_ADD_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002888 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002889 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002890 case OP_MUL_INT_LIT8:
2891 case OP_MUL_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002892 op = kOpMul;
2893 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002894 case OP_AND_INT_LIT8:
2895 case OP_AND_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002896 op = kOpAnd;
2897 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002898 case OP_OR_INT_LIT8:
2899 case OP_OR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002900 op = kOpOr;
2901 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002902 case OP_XOR_INT_LIT8:
2903 case OP_XOR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002904 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002905 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002906 case OP_SHL_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002907 shiftOp = true;
2908 op = kOpLsl;
2909 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002910 case OP_SHR_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002911 shiftOp = true;
2912 op = kOpAsr;
2913 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002914 case OP_USHR_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002915 shiftOp = true;
2916 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002917 break;
2918
2919 case OP_DIV_INT_LIT8:
2920 case OP_DIV_INT_LIT16:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002921 case OP_REM_INT_LIT8:
2922 case OP_REM_INT_LIT16:
2923 if (lit == 0) {
2924 /* Let the interpreter deal with div by 0 */
2925 genInterpSingleStep(cUnit, mir);
2926 return false;
2927 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002928 loadValueDirectFixed(cUnit, rlSrc, r0);
2929 clobberReg(cUnit, r0);
2930 if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2931 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2932 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2933 isDiv = true;
2934 } else {
2935 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2936 isDiv = false;
2937 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002938 loadConstant(cUnit, r1, lit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002939 opReg(cUnit, kOpBlx, r2);
2940 clobberCallRegs(cUnit);
2941 if (isDiv)
2942 rlResult = getReturnLoc(cUnit);
2943 else
2944 rlResult = getReturnLocAlt(cUnit);
2945 storeValue(cUnit, rlDest, rlResult);
2946 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002947 break;
2948 default:
2949 return true;
2950 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002951 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2952 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2953 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2954 if (shiftOp && (lit == 0)) {
2955 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2956 } else {
2957 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2958 }
2959 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002960 return false;
2961}
2962
2963static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
2964{
2965 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2966 int fieldOffset;
2967
2968 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
2969 InstField *pInstField = (InstField *)
2970 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
Ben Chengba4fc8b2009-06-01 13:00:29 -07002971
2972 assert(pInstField != NULL);
2973 fieldOffset = pInstField->byteOffset;
2974 } else {
Ben Chenga0e7b602009-10-13 23:09:01 -07002975 /* Deliberately break the code while make the compiler happy */
2976 fieldOffset = -1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002977 }
2978 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002979 case OP_NEW_ARRAY: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002980 // Generates a call - use explicit registers
2981 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2982 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2983 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002984 void *classPtr = (void*)
2985 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
2986 assert(classPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002987 genExportPC(cUnit, mir);
2988 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002989 loadConstant(cUnit, r0, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07002990 loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
Ben Cheng4f489172009-09-27 17:08:35 -07002991 /*
2992 * "len < 0": bail to the interpreter to re-execute the
2993 * instruction
2994 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002995 ArmLIR *pcrLabel =
Bill Buzbee1465db52009-09-23 17:17:35 -07002996 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002997 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07002998 opReg(cUnit, kOpBlx, r3);
2999 clobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07003000 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07003001 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3002 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07003003 /*
3004 * OOM exception needs to be thrown here and cannot re-execute
3005 */
3006 loadConstant(cUnit, r0,
3007 (int) (cUnit->method->insns + mir->offset));
3008 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3009 /* noreturn */
3010
Bill Buzbee1465db52009-09-23 17:17:35 -07003011 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07003012 target->defMask = ENCODE_ALL;
3013 branchOver->generic.target = (LIR *) target;
Bill Buzbee1465db52009-09-23 17:17:35 -07003014 rlResult = getReturnLoc(cUnit);
3015 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003016 break;
3017 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003018 case OP_INSTANCE_OF: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003019 // May generate a call - use explicit registers
3020 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3021 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
3022 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003023 ClassObject *classPtr =
3024 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
3025 assert(classPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07003026 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003027 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07003028//TUNING: compare to 0 primative to allow use of CB[N]Z
Bill Buzbee1465db52009-09-23 17:17:35 -07003029 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07003030 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee1465db52009-09-23 17:17:35 -07003031 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003032 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003033 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07003034 /* r1 now contains object->clazz */
3035 loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07003036 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee1465db52009-09-23 17:17:35 -07003037 opRegReg(cUnit, kOpCmp, r1, r2);
3038 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
3039 genRegCopy(cUnit, r0, r1);
3040 genRegCopy(cUnit, r1, r2);
3041 opReg(cUnit, kOpBlx, r3);
3042 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003043 /* branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07003044 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07003045 target->defMask = ENCODE_ALL;
Bill Buzbee1465db52009-09-23 17:17:35 -07003046 rlResult = getReturnLoc(cUnit);
3047 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003048 branch1->generic.target = (LIR *)target;
3049 branch2->generic.target = (LIR *)target;
3050 break;
3051 }
3052 case OP_IGET_WIDE:
3053 genIGetWide(cUnit, mir, fieldOffset);
3054 break;
3055 case OP_IGET:
3056 case OP_IGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003057 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003058 break;
3059 case OP_IGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003060 genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003061 break;
3062 case OP_IGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003063 genIGet(cUnit, mir, kSignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003064 break;
3065 case OP_IGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003066 genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003067 break;
3068 case OP_IGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003069 genIGet(cUnit, mir, kSignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003070 break;
3071 case OP_IPUT_WIDE:
3072 genIPutWide(cUnit, mir, fieldOffset);
3073 break;
3074 case OP_IPUT:
3075 case OP_IPUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003076 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003077 break;
3078 case OP_IPUT_SHORT:
3079 case OP_IPUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003080 genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003081 break;
3082 case OP_IPUT_BYTE:
3083 case OP_IPUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003084 genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003085 break;
3086 default:
3087 return true;
3088 }
3089 return false;
3090}
3091
3092static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
3093{
3094 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3095 int fieldOffset = mir->dalvikInsn.vC;
3096 switch (dalvikOpCode) {
3097 case OP_IGET_QUICK:
3098 case OP_IGET_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07003099 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003100 break;
3101 case OP_IPUT_QUICK:
3102 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07003103 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003104 break;
3105 case OP_IGET_WIDE_QUICK:
3106 genIGetWide(cUnit, mir, fieldOffset);
3107 break;
3108 case OP_IPUT_WIDE_QUICK:
3109 genIPutWide(cUnit, mir, fieldOffset);
3110 break;
3111 default:
3112 return true;
3113 }
3114 return false;
3115
3116}
3117
3118/* Compare agaist zero */
3119static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003120 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003121{
3122 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003123 ArmConditionCode cond;
Bill Buzbee1465db52009-09-23 17:17:35 -07003124 RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
3125 RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003126
Bill Buzbee1465db52009-09-23 17:17:35 -07003127 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
3128 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
3129 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003130
3131 switch (dalvikOpCode) {
3132 case OP_IF_EQ:
Bill Buzbee1465db52009-09-23 17:17:35 -07003133 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003134 break;
3135 case OP_IF_NE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003136 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003137 break;
3138 case OP_IF_LT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003139 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003140 break;
3141 case OP_IF_GE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003142 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003143 break;
3144 case OP_IF_GT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003145 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003146 break;
3147 case OP_IF_LE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003148 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003149 break;
3150 default:
3151 cond = 0;
3152 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
3153 dvmAbort();
3154 }
3155 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
3156 /* This mostly likely will be optimized away in a later phase */
3157 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
3158 return false;
3159}
3160
3161static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
3162{
3163 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003164
3165 switch (opCode) {
3166 case OP_MOVE_16:
3167 case OP_MOVE_OBJECT_16:
3168 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07003169 case OP_MOVE_OBJECT_FROM16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003170 storeValue(cUnit, getDestLoc(cUnit, mir, 0),
3171 getSrcLoc(cUnit, mir, 0));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003172 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003173 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003174 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07003175 case OP_MOVE_WIDE_FROM16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003176 storeValueWide(cUnit, getDestLocWide(cUnit, mir, 0, 1),
3177 getSrcLocWide(cUnit, mir, 0, 1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003178 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003179 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003180 default:
3181 return true;
3182 }
3183 return false;
3184}
3185
3186static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
3187{
3188 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07003189 RegLocation rlSrc1;
3190 RegLocation rlSrc2;
3191 RegLocation rlDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003192
3193 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003194 return handleArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07003195 }
3196
Bill Buzbee1465db52009-09-23 17:17:35 -07003197 /* APUTs have 3 sources and no targets */
3198 if (mir->ssaRep->numDefs == 0) {
3199 if (mir->ssaRep->numUses == 3) {
3200 rlDest = getSrcLoc(cUnit, mir, 0);
3201 rlSrc1 = getSrcLoc(cUnit, mir, 1);
3202 rlSrc2 = getSrcLoc(cUnit, mir, 2);
3203 } else {
3204 assert(mir->ssaRep->numUses == 4);
3205 rlDest = getSrcLocWide(cUnit, mir, 0, 1);
3206 rlSrc1 = getSrcLoc(cUnit, mir, 2);
3207 rlSrc2 = getSrcLoc(cUnit, mir, 3);
3208 }
3209 } else {
3210 /* Two sources and 1 dest. Deduce the operand sizes */
3211 if (mir->ssaRep->numUses == 4) {
3212 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
3213 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
3214 } else {
3215 assert(mir->ssaRep->numUses == 2);
3216 rlSrc1 = getSrcLoc(cUnit, mir, 0);
3217 rlSrc2 = getSrcLoc(cUnit, mir, 1);
3218 }
3219 if (mir->ssaRep->numDefs == 2) {
3220 rlDest = getDestLocWide(cUnit, mir, 0, 1);
3221 } else {
3222 assert(mir->ssaRep->numDefs == 1);
3223 rlDest = getDestLoc(cUnit, mir, 0);
3224 }
3225 }
3226
3227
Ben Chengba4fc8b2009-06-01 13:00:29 -07003228 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07003229 case OP_CMPL_FLOAT:
3230 case OP_CMPG_FLOAT:
3231 case OP_CMPL_DOUBLE:
3232 case OP_CMPG_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003233 return handleCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003234 case OP_CMP_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07003235 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003236 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003237 case OP_AGET_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003238 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003239 break;
3240 case OP_AGET:
3241 case OP_AGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003242 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003243 break;
3244 case OP_AGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003245 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003246 break;
3247 case OP_AGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003248 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003249 break;
3250 case OP_AGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003251 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003252 break;
3253 case OP_AGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003254 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003255 break;
3256 case OP_APUT_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003257 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003258 break;
3259 case OP_APUT:
3260 case OP_APUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003261 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003262 break;
3263 case OP_APUT_SHORT:
3264 case OP_APUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003265 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003266 break;
3267 case OP_APUT_BYTE:
3268 case OP_APUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003269 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003270 break;
3271 default:
3272 return true;
3273 }
3274 return false;
3275}
3276
3277static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
3278{
3279 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3280 switch (dalvikOpCode) {
3281 case OP_FILL_ARRAY_DATA: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003282 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3283 // Making a call - use explicit registers
3284 genExportPC(cUnit, mir);
3285 loadValueDirectFixed(cUnit, rlSrc, r0);
3286 loadConstant(cUnit, r3, (int)dvmInterpHandleFillArrayData);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003287 loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
3288 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -07003289 opReg(cUnit, kOpBlx, r2);
3290 clobberCallRegs(cUnit);
Ben Chenge9695e52009-06-16 16:11:47 -07003291 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003292 break;
3293 }
3294 /*
3295 * TODO
3296 * - Add a 1 to 3-entry per-location cache here to completely
3297 * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
Bill Buzbee1465db52009-09-23 17:17:35 -07003298 * - Use out-of-line handlers for both of these. These ops
3299 * handle their own register allocation.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003300 */
3301 case OP_PACKED_SWITCH:
3302 case OP_SPARSE_SWITCH: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003303 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3304 loadValueDirectFixed(cUnit, rlSrc, r1);
3305 lockAllTemps(cUnit);
3306 // Exit to the interpreter, setting up r4PC
Ben Chengba4fc8b2009-06-01 13:00:29 -07003307 if (dalvikOpCode == OP_PACKED_SWITCH) {
3308 loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
3309 } else {
3310 loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
3311 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003312 loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
3313 (int) (cUnit->method->insns + mir->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -07003314 opReg(cUnit, kOpBlx, r4PC);
3315 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003316 loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07003317 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3318 jitToInterpEntries.dvmJitToInterpNoChain), r2);
Bill Buzbee1465db52009-09-23 17:17:35 -07003319 opRegReg(cUnit, kOpAdd, r0, r0);
3320 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
3321 opReg(cUnit, kOpBlx, r2);
3322 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003323 break;
3324 }
3325 default:
3326 return true;
3327 }
3328 return false;
3329}
3330
3331static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003332 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003333{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003334 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003335 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003336
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003337 if (bb->fallThrough != NULL)
3338 retChainingCell = &labelList[bb->fallThrough->id];
3339
Ben Chengba4fc8b2009-06-01 13:00:29 -07003340 DecodedInstruction *dInsn = &mir->dalvikInsn;
3341 switch (mir->dalvikInsn.opCode) {
3342 /*
3343 * calleeMethod = this->clazz->vtable[
3344 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3345 * ]
3346 */
3347 case OP_INVOKE_VIRTUAL:
3348 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003349 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003350 int methodIndex =
3351 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3352 methodIndex;
3353
3354 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3355 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3356 else
3357 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3358
Ben Cheng38329f52009-07-07 14:19:20 -07003359 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3360 retChainingCell,
3361 predChainingCell,
3362 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003363 break;
3364 }
3365 /*
3366 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3367 * ->pResMethods[BBBB]->methodIndex]
3368 */
3369 /* TODO - not excersized in RunPerf.jar */
3370 case OP_INVOKE_SUPER:
3371 case OP_INVOKE_SUPER_RANGE: {
3372 int mIndex = cUnit->method->clazz->pDvmDex->
3373 pResMethods[dInsn->vB]->methodIndex;
3374 const Method *calleeMethod =
3375 cUnit->method->clazz->super->vtable[mIndex];
3376
3377 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3378 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3379 else
3380 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3381
3382 /* r0 = calleeMethod */
3383 loadConstant(cUnit, r0, (int) calleeMethod);
3384
Ben Cheng38329f52009-07-07 14:19:20 -07003385 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3386 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003387 break;
3388 }
3389 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3390 case OP_INVOKE_DIRECT:
3391 case OP_INVOKE_DIRECT_RANGE: {
3392 const Method *calleeMethod =
3393 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3394
3395 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3396 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3397 else
3398 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3399
3400 /* r0 = calleeMethod */
3401 loadConstant(cUnit, r0, (int) calleeMethod);
3402
Ben Cheng38329f52009-07-07 14:19:20 -07003403 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3404 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003405 break;
3406 }
3407 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3408 case OP_INVOKE_STATIC:
3409 case OP_INVOKE_STATIC_RANGE: {
3410 const Method *calleeMethod =
3411 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3412
3413 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3414 genProcessArgsNoRange(cUnit, mir, dInsn,
3415 NULL /* no null check */);
3416 else
3417 genProcessArgsRange(cUnit, mir, dInsn,
3418 NULL /* no null check */);
3419
3420 /* r0 = calleeMethod */
3421 loadConstant(cUnit, r0, (int) calleeMethod);
3422
Ben Cheng38329f52009-07-07 14:19:20 -07003423 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3424 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003425 break;
3426 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003427 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -07003428 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3429 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003430 *
3431 * Given "invoke-interface {v0}", the following is the generated code:
3432 *
3433 * 0x426a9abe : ldr r0, [r5, #0] --+
3434 * 0x426a9ac0 : mov r7, r5 |
3435 * 0x426a9ac2 : sub r7, #24 |
3436 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3437 * 0x426a9ac6 : beq 0x426a9afe |
3438 * 0x426a9ac8 : stmia r7, <r0> --+
3439 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3440 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3441 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3442 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3443 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3444 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3445 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
Ben Chenga8e64a72009-10-20 13:01:36 -07003446 * 0x426a9ad8 : mov r8, r1 --+
3447 * 0x426a9ada : mov r9, r2 |
3448 * 0x426a9adc : mov r10, r3 |
Ben Cheng38329f52009-07-07 14:19:20 -07003449 * 0x426a9ade : mov r0, r3 |
3450 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3451 * 0x426a9ae2 : ldr r2, [pc, #76] |
3452 * 0x426a9ae4 : ldr r3, [pc, #68] |
3453 * 0x426a9ae6 : ldr r7, [pc, #64] |
3454 * 0x426a9ae8 : blx r7 --+
Ben Chenga8e64a72009-10-20 13:01:36 -07003455 * 0x426a9aea : mov r1, r8 --> r1 <- rechain count
Ben Cheng38329f52009-07-07 14:19:20 -07003456 * 0x426a9aec : cmp r1, #0 --> compare against 0
3457 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3458 * 0x426a9af0 : ldr r7, [r6, #96] --+
Ben Chenga8e64a72009-10-20 13:01:36 -07003459 * 0x426a9af2 : mov r2, r9 | dvmJitToPatchPredictedChain
3460 * 0x426a9af4 : mov r3, r10 |
Ben Cheng38329f52009-07-07 14:19:20 -07003461 * 0x426a9af6 : blx r7 --+
3462 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3463 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3464 * 0x426a9afc : blx_2 see above --+
3465 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3466 * 0x426a9afe (0042): ldr r0, [pc, #52]
3467 * Exception_Handling:
3468 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3469 * 0x426a9b02 (0046): blx r1
3470 * 0x426a9b04 (0048): .align4
3471 * -------- chaining cell (hot): 0x0021
3472 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3473 * 0x426a9b06 (004a): blx r0
3474 * 0x426a9b08 (004c): data 0x7872(30834)
3475 * 0x426a9b0a (004e): data 0x428b(17035)
3476 * 0x426a9b0c (0050): .align4
3477 * -------- chaining cell (predicted)
3478 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3479 * 0x426a9b0e (0052): data 0x0000(0)
3480 * 0x426a9b10 (0054): data 0x0000(0) --> class
3481 * 0x426a9b12 (0056): data 0x0000(0)
3482 * 0x426a9b14 (0058): data 0x0000(0) --> method
3483 * 0x426a9b16 (005a): data 0x0000(0)
3484 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3485 * 0x426a9b1a (005e): data 0x0000(0)
3486 * 0x426a9b28 (006c): .word (0xad0392a5)
3487 * 0x426a9b2c (0070): .word (0x6e750)
3488 * 0x426a9b30 (0074): .word (0x4109a618)
3489 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003490 */
3491 case OP_INVOKE_INTERFACE:
3492 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003493 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003494 int methodIndex = dInsn->vB;
3495
Bill Buzbee1465db52009-09-23 17:17:35 -07003496 /* Ensure that nothing is both live and dirty */
3497 flushAllRegs(cUnit);
3498
Ben Chengba4fc8b2009-06-01 13:00:29 -07003499 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3500 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3501 else
3502 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3503
Ben Cheng38329f52009-07-07 14:19:20 -07003504 /* "this" is already left in r0 by genProcessArgs* */
3505
3506 /* r4PC = dalvikCallsite */
3507 loadConstant(cUnit, r4PC,
3508 (int) (cUnit->method->insns + mir->offset));
3509
3510 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003511 ArmLIR *addrRetChain =
Bill Buzbee1465db52009-09-23 17:17:35 -07003512 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003513 addrRetChain->generic.target = (LIR *) retChainingCell;
3514
3515 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003516 ArmLIR *predictedChainingCell =
Bill Buzbee1465db52009-09-23 17:17:35 -07003517 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003518 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3519
3520 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3521
3522 /* return through lr - jump to the chaining cell */
3523 genUnconditionalBranch(cUnit, predChainingCell);
3524
3525 /*
3526 * null-check on "this" may have been eliminated, but we still need
3527 * a PC-reconstruction label for stack overflow bailout.
3528 */
3529 if (pcrLabel == NULL) {
3530 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003531 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003532 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003533 pcrLabel->operands[0] = dPC;
3534 pcrLabel->operands[1] = mir->offset;
3535 /* Insert the place holder to the growable list */
3536 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3537 }
3538
3539 /* return through lr+2 - punt to the interpreter */
3540 genUnconditionalBranch(cUnit, pcrLabel);
3541
3542 /*
3543 * return through lr+4 - fully resolve the callee method.
3544 * r1 <- count
3545 * r2 <- &predictedChainCell
3546 * r3 <- this->class
3547 * r4 <- dPC
3548 * r7 <- this->class->vtable
3549 */
3550
3551 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee1465db52009-09-23 17:17:35 -07003552 genRegCopy(cUnit, r8, r1);
3553 genRegCopy(cUnit, r9, r2);
3554 genRegCopy(cUnit, r10, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003555
Ben Chengba4fc8b2009-06-01 13:00:29 -07003556 /* r0 now contains this->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07003557 genRegCopy(cUnit, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003558
3559 /* r1 = BBBB */
3560 loadConstant(cUnit, r1, dInsn->vB);
3561
3562 /* r2 = method (caller) */
3563 loadConstant(cUnit, r2, (int) cUnit->method);
3564
3565 /* r3 = pDvmDex */
3566 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3567
3568 loadConstant(cUnit, r7,
3569 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee1465db52009-09-23 17:17:35 -07003570 opReg(cUnit, kOpBlx, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003571
3572 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3573
Bill Buzbee1465db52009-09-23 17:17:35 -07003574 genRegCopy(cUnit, r1, r8);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003575
Ben Cheng38329f52009-07-07 14:19:20 -07003576 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07003577 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003578
Bill Buzbee1465db52009-09-23 17:17:35 -07003579 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07003580
Bill Buzbee270c1d62009-08-13 16:58:07 -07003581 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3582 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003583
Bill Buzbee1465db52009-09-23 17:17:35 -07003584 genRegCopy(cUnit, r2, r9);
3585 genRegCopy(cUnit, r3, r10);
Ben Cheng38329f52009-07-07 14:19:20 -07003586
3587 /*
3588 * r0 = calleeMethod
3589 * r2 = &predictedChainingCell
3590 * r3 = class
3591 *
3592 * &returnChainingCell has been loaded into r1 but is not needed
3593 * when patching the chaining cell and will be clobbered upon
3594 * returning so it will be reconstructed again.
3595 */
Bill Buzbee1465db52009-09-23 17:17:35 -07003596 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003597
3598 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07003599 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003600 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003601
3602 bypassRechaining->generic.target = (LIR *) addrRetChain;
3603
Ben Chengba4fc8b2009-06-01 13:00:29 -07003604 /*
3605 * r0 = this, r1 = calleeMethod,
3606 * r1 = &ChainingCell,
3607 * r4PC = callsiteDPC,
3608 */
3609 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3610#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003611 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003612#endif
3613 /* Handle exceptions using the interpreter */
3614 genTrap(cUnit, mir->offset, pcrLabel);
3615 break;
3616 }
3617 /* NOP */
3618 case OP_INVOKE_DIRECT_EMPTY: {
3619 return false;
3620 }
3621 case OP_FILLED_NEW_ARRAY:
3622 case OP_FILLED_NEW_ARRAY_RANGE: {
3623 /* Just let the interpreter deal with these */
3624 genInterpSingleStep(cUnit, mir);
3625 break;
3626 }
3627 default:
3628 return true;
3629 }
3630 return false;
3631}
3632
3633static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003634 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003635{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003636 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3637 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3638 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003639
3640 DecodedInstruction *dInsn = &mir->dalvikInsn;
3641 switch (mir->dalvikInsn.opCode) {
3642 /* calleeMethod = this->clazz->vtable[BBBB] */
3643 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3644 case OP_INVOKE_VIRTUAL_QUICK: {
3645 int methodIndex = dInsn->vB;
3646 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3647 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3648 else
3649 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3650
Ben Cheng38329f52009-07-07 14:19:20 -07003651 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3652 retChainingCell,
3653 predChainingCell,
3654 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003655 break;
3656 }
3657 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3658 case OP_INVOKE_SUPER_QUICK:
3659 case OP_INVOKE_SUPER_QUICK_RANGE: {
3660 const Method *calleeMethod =
3661 cUnit->method->clazz->super->vtable[dInsn->vB];
3662
3663 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3664 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3665 else
3666 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3667
3668 /* r0 = calleeMethod */
3669 loadConstant(cUnit, r0, (int) calleeMethod);
3670
Ben Cheng38329f52009-07-07 14:19:20 -07003671 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3672 calleeMethod);
3673 /* Handle exceptions using the interpreter */
3674 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003675 break;
3676 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003677 default:
3678 return true;
3679 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003680 return false;
3681}
3682
3683/*
3684 * NOTE: We assume here that the special native inline routines
3685 * are side-effect free. By making this assumption, we can safely
3686 * re-execute the routine from the interpreter if it decides it
3687 * wants to throw an exception. We still need to EXPORT_PC(), though.
3688 */
3689static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3690{
3691 DecodedInstruction *dInsn = &mir->dalvikInsn;
3692 switch( mir->dalvikInsn.opCode) {
3693 case OP_EXECUTE_INLINE: {
3694 unsigned int i;
3695 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003696 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003697 int operation = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07003698 int tReg1;
3699 int tReg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003700 switch (operation) {
3701 case INLINE_EMPTYINLINEMETHOD:
3702 return false; /* Nop */
3703 case INLINE_STRING_LENGTH:
3704 return genInlinedStringLength(cUnit, mir);
3705 case INLINE_MATH_ABS_INT:
3706 return genInlinedAbsInt(cUnit, mir);
3707 case INLINE_MATH_ABS_LONG:
3708 return genInlinedAbsLong(cUnit, mir);
3709 case INLINE_MATH_MIN_INT:
3710 return genInlinedMinMaxInt(cUnit, mir, true);
3711 case INLINE_MATH_MAX_INT:
3712 return genInlinedMinMaxInt(cUnit, mir, false);
3713 case INLINE_STRING_CHARAT:
3714 return genInlinedStringCharAt(cUnit, mir);
3715 case INLINE_MATH_SQRT:
3716 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003717 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003718 else
3719 break; /* Handle with C routine */
3720 case INLINE_MATH_COS:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003721 case INLINE_MATH_SIN:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003722 break; /* Handle with C routine */
3723 case INLINE_MATH_ABS_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003724 if (genInlinedAbsFloat(cUnit, mir))
3725 return false;
3726 else
3727 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003728 case INLINE_MATH_ABS_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003729 if (genInlinedAbsDouble(cUnit, mir))
3730 return false;
3731 else
3732 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003733 case INLINE_STRING_COMPARETO:
3734 case INLINE_STRING_EQUALS:
Bill Buzbee12ba0152009-09-03 14:03:09 -07003735 case INLINE_STRING_INDEXOF_I:
3736 case INLINE_STRING_INDEXOF_II:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003737 break;
3738 default:
3739 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003740 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003741 clobberCallRegs(cUnit);
3742 clobberReg(cUnit, r4PC);
3743 clobberReg(cUnit, r7);
3744 opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3745 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003746 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
Bill Buzbee1465db52009-09-23 17:17:35 -07003747 genExportPC(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003748 for (i=0; i < dInsn->vA; i++) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003749 loadValueDirect(cUnit, getSrcLoc(cUnit, mir, i), i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003750 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003751 opReg(cUnit, kOpBlx, r4PC);
3752 opRegImm(cUnit, kOpAdd, r13, 8);
Ben Chenge9695e52009-06-16 16:11:47 -07003753 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003754 break;
3755 }
3756 default:
3757 return true;
3758 }
3759 return false;
3760}
3761
3762static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
3763{
Bill Buzbee1465db52009-09-23 17:17:35 -07003764 //TUNING: We're using core regs here - not optimal when target is a double
3765 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
3766 RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
3767 loadConstantValue(cUnit, rlResult.lowReg,
3768 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
3769 loadConstantValue(cUnit, rlResult.highReg,
3770 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
3771 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003772 return false;
3773}
3774
Ben Chengba4fc8b2009-06-01 13:00:29 -07003775/*
3776 * The following are special processing routines that handle transfer of
3777 * controls between compiled code and the interpreter. Certain VM states like
3778 * Dalvik PC and special-purpose registers are reconstructed here.
3779 */
3780
Ben Cheng1efc9c52009-06-08 18:25:27 -07003781/* Chaining cell for code that may need warmup. */
3782static void handleNormalChainingCell(CompilationUnit *cUnit,
3783 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003784{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003785 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3786 jitToInterpEntries.dvmJitToInterpNormal), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003787 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003788 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3789}
3790
3791/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07003792 * Chaining cell for instructions that immediately following already translated
3793 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003794 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07003795static void handleHotChainingCell(CompilationUnit *cUnit,
3796 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003797{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003798 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3799 jitToInterpEntries.dvmJitToTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003800 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003801 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3802}
3803
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003804#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07003805/* Chaining cell for branches that branch back into the same basic block */
3806static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
3807 unsigned int offset)
3808{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003809#if defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07003810 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Jeff Hao97319a82009-08-12 16:57:15 -07003811 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003812#else
Bill Buzbee1465db52009-09-23 17:17:35 -07003813 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07003814 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
3815#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07003816 newLIR1(cUnit, kThumbBlxR, r0);
Jeff Hao97319a82009-08-12 16:57:15 -07003817 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
3818}
3819
3820#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07003821/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07003822static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
3823 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003824{
Bill Buzbee270c1d62009-08-13 16:58:07 -07003825 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3826 jitToInterpEntries.dvmJitToTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07003827 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003828 addWordData(cUnit, (int) (callee->insns), true);
3829}
3830
Ben Cheng38329f52009-07-07 14:19:20 -07003831/* Chaining cell for monomorphic method invocations. */
3832static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
3833{
3834
3835 /* Should not be executed in the initial state */
3836 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
3837 /* To be filled: class */
3838 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
3839 /* To be filled: method */
3840 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
3841 /*
3842 * Rechain count. The initial value of 0 here will trigger chaining upon
3843 * the first invocation of this callsite.
3844 */
3845 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
3846}
3847
Ben Chengba4fc8b2009-06-01 13:00:29 -07003848/* Load the Dalvik PC into r0 and jump to the specified target */
3849static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003850 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003851{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003852 ArmLIR **pcrLabel =
3853 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003854 int numElems = cUnit->pcReconstructionList.numUsed;
3855 int i;
3856 for (i = 0; i < numElems; i++) {
3857 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
3858 /* r0 = dalvik PC */
3859 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
3860 genUnconditionalBranch(cUnit, targetLabel);
3861 }
3862}
3863
Bill Buzbee1465db52009-09-23 17:17:35 -07003864static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
3865 "kMirOpPhi",
3866 "kMirOpNullNRangeUpCheck",
3867 "kMirOpNullNRangeDownCheck",
3868 "kMirOpLowerBound",
3869 "kMirOpPunt",
Ben Cheng4238ec22009-08-24 16:32:22 -07003870};
3871
3872/*
3873 * vA = arrayReg;
3874 * vB = idxReg;
3875 * vC = endConditionReg;
3876 * arg[0] = maxC
3877 * arg[1] = minC
3878 * arg[2] = loopBranchConditionCode
3879 */
3880static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
3881{
Bill Buzbee1465db52009-09-23 17:17:35 -07003882 /*
3883 * NOTE: these synthesized blocks don't have ssa names assigned
3884 * for Dalvik registers. However, because they dominate the following
3885 * blocks we can simply use the Dalvik name w/ subscript 0 as the
3886 * ssa name.
3887 */
Ben Cheng4238ec22009-08-24 16:32:22 -07003888 DecodedInstruction *dInsn = &mir->dalvikInsn;
3889 const int lenOffset = offsetof(ArrayObject, length);
Ben Cheng4238ec22009-08-24 16:32:22 -07003890 const int maxC = dInsn->arg[0];
3891 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07003892 int regLength;
3893 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3894 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
Ben Cheng4238ec22009-08-24 16:32:22 -07003895
3896 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07003897 rlArray = loadValue(cUnit, rlArray, kCoreReg);
3898 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
3899 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003900 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3901
3902 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07003903 regLength = allocTemp(cUnit);
3904 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07003905
3906 int delta = maxC;
3907 /*
3908 * If the loop end condition is ">=" instead of ">", then the largest value
3909 * of the index is "endCondition - 1".
3910 */
3911 if (dInsn->arg[2] == OP_IF_GE) {
3912 delta--;
3913 }
3914
3915 if (delta) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003916 int tReg = allocTemp(cUnit);
3917 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
3918 rlIdxEnd.lowReg = tReg;
3919 freeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003920 }
3921 /* Punt if "regIdxEnd < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003922 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07003923 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003924}
3925
3926/*
3927 * vA = arrayReg;
3928 * vB = idxReg;
3929 * vC = endConditionReg;
3930 * arg[0] = maxC
3931 * arg[1] = minC
3932 * arg[2] = loopBranchConditionCode
3933 */
3934static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
3935{
3936 DecodedInstruction *dInsn = &mir->dalvikInsn;
3937 const int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07003938 const int regLength = allocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07003939 const int maxC = dInsn->arg[0];
3940 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07003941 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
3942 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
Ben Cheng4238ec22009-08-24 16:32:22 -07003943
3944 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07003945 rlArray = loadValue(cUnit, rlArray, kCoreReg);
3946 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
3947 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003948 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3949
3950 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07003951 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07003952
3953 if (maxC) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003954 int tReg = allocTemp(cUnit);
3955 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
3956 rlIdxInit.lowReg = tReg;
3957 freeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003958 }
3959
3960 /* Punt if "regIdxInit < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003961 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07003962 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07003963}
3964
3965/*
3966 * vA = idxReg;
3967 * vB = minC;
3968 */
3969static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
3970{
3971 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -07003972 const int minC = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07003973 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
Ben Cheng4238ec22009-08-24 16:32:22 -07003974
3975 /* regIdx <- initial index value */
Bill Buzbee1465db52009-09-23 17:17:35 -07003976 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003977
3978 /* Punt if "regIdxInit + minC >= 0" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07003979 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07003980 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
3981}
3982
3983/* Extended MIR instructions like PHI */
3984static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
3985{
Bill Buzbee1465db52009-09-23 17:17:35 -07003986 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
Ben Cheng4238ec22009-08-24 16:32:22 -07003987 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
3988 false);
3989 strcpy(msg, extendedMIROpNames[opOffset]);
Bill Buzbee1465db52009-09-23 17:17:35 -07003990 newLIR1(cUnit, kArmPseudoExtended, (int) msg);
Ben Cheng4238ec22009-08-24 16:32:22 -07003991
3992 switch (mir->dalvikInsn.opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003993 case kMirOpPhi: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003994 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07003995 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07003996 break;
3997 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003998 case kMirOpNullNRangeUpCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07003999 genHoistedChecksForCountUpLoop(cUnit, mir);
4000 break;
4001 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004002 case kMirOpNullNRangeDownCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004003 genHoistedChecksForCountDownLoop(cUnit, mir);
4004 break;
4005 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004006 case kMirOpLowerBound: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004007 genHoistedLowerBoundCheck(cUnit, mir);
4008 break;
4009 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004010 case kMirOpPunt: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004011 genUnconditionalBranch(cUnit,
4012 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4013 break;
4014 }
4015 default:
4016 break;
4017 }
4018}
4019
4020/*
4021 * Create a PC-reconstruction cell for the starting offset of this trace.
4022 * Since the PCR cell is placed near the end of the compiled code which is
4023 * usually out of range for a conditional branch, we put two branches (one
4024 * branch over to the loop body and one layover branch to the actual PCR) at the
4025 * end of the entry block.
4026 */
4027static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
4028 ArmLIR *bodyLabel)
4029{
4030 /* Set up the place holder to reconstruct this Dalvik PC */
4031 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004032 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng4238ec22009-08-24 16:32:22 -07004033 pcrLabel->operands[0] =
4034 (int) (cUnit->method->insns + entry->startOffset);
4035 pcrLabel->operands[1] = entry->startOffset;
4036 /* Insert the place holder to the growable list */
4037 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
4038
4039 /*
4040 * Next, create two branches - one branch over to the loop body and the
4041 * other branch to the PCR cell to punt.
4042 */
4043 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004044 branchToBody->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07004045 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07004046 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07004047 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
4048
4049 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004050 branchToPCR->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07004051 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07004052 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004053 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
4054}
4055
Ben Chengba4fc8b2009-06-01 13:00:29 -07004056void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
4057{
4058 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004059 ArmLIR *labelList =
4060 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004061 GrowableList chainingListByType[kChainingCellLast];
Ben Chengba4fc8b2009-06-01 13:00:29 -07004062 int i;
4063
4064 /*
Ben Cheng38329f52009-07-07 14:19:20 -07004065 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07004066 */
Bill Buzbee1465db52009-09-23 17:17:35 -07004067 for (i = 0; i < kChainingCellLast; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004068 dvmInitGrowableList(&chainingListByType[i], 2);
4069 }
4070
4071 BasicBlock **blockList = cUnit->blockList;
4072
Bill Buzbee6e963e12009-06-17 16:56:19 -07004073 if (cUnit->executionCount) {
4074 /*
4075 * Reserve 6 bytes at the beginning of the trace
4076 * +----------------------------+
4077 * | execution count (4 bytes) |
4078 * +----------------------------+
4079 * | chain cell offset (2 bytes)|
4080 * +----------------------------+
4081 * ...and then code to increment the execution
4082 * count:
4083 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
4084 * sub r0, #10 @ back up to addr of executionCount
4085 * ldr r1, [r0]
4086 * add r1, #1
4087 * str r1, [r0]
4088 */
Bill Buzbee1465db52009-09-23 17:17:35 -07004089 newLIR1(cUnit, kArm16BitData, 0);
4090 newLIR1(cUnit, kArm16BitData, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07004091 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004092 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004093 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07004094 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee1465db52009-09-23 17:17:35 -07004095 newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
4096 newLIR2(cUnit, kThumbSubRI8, r0, 10);
4097 newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
4098 newLIR2(cUnit, kThumbAddRI8, r1, 1);
4099 newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004100 } else {
4101 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07004102 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004103 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004104 cUnit->headerSize = 2;
4105 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07004106
Ben Chengba4fc8b2009-06-01 13:00:29 -07004107 /* Handle the content in each basic block */
4108 for (i = 0; i < cUnit->numBlocks; i++) {
4109 blockList[i]->visited = true;
4110 MIR *mir;
4111
4112 labelList[i].operands[0] = blockList[i]->startOffset;
4113
Bill Buzbee1465db52009-09-23 17:17:35 -07004114 if (blockList[i]->blockType >= kChainingCellLast) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004115 /*
4116 * Append the label pseudo LIR first. Chaining cells will be handled
4117 * separately afterwards.
4118 */
4119 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
4120 }
4121
Bill Buzbee1465db52009-09-23 17:17:35 -07004122 if (blockList[i]->blockType == kEntryBlock) {
4123 labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07004124 if (blockList[i]->firstMIRInsn == NULL) {
4125 continue;
4126 } else {
4127 setupLoopEntryBlock(cUnit, blockList[i],
4128 &labelList[blockList[i]->fallThrough->id]);
4129 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004130 } else if (blockList[i]->blockType == kExitBlock) {
4131 labelList[i].opCode = ARM_PSEUDO_kExitBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07004132 goto gen_fallthrough;
Bill Buzbee1465db52009-09-23 17:17:35 -07004133 } else if (blockList[i]->blockType == kDalvikByteCode) {
4134 labelList[i].opCode = kArmPseudoNormalBlockLabel;
Ben Chenge9695e52009-06-16 16:11:47 -07004135 /* Reset the register state */
Bill Buzbee1465db52009-09-23 17:17:35 -07004136 resetRegPool(cUnit);
4137 clobberAllRegs(cUnit);
4138 resetNullCheckTracker(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004139 } else {
4140 switch (blockList[i]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004141 case kChainingCellNormal:
4142 labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004143 /* handle the codegen later */
4144 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004145 &chainingListByType[kChainingCellNormal], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004146 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004147 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07004148 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004149 ARM_PSEUDO_kChainingCellInvokeSingleton;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004150 labelList[i].operands[0] =
4151 (int) blockList[i]->containingMethod;
4152 /* handle the codegen later */
4153 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004154 &chainingListByType[kChainingCellInvokeSingleton],
Ben Cheng38329f52009-07-07 14:19:20 -07004155 (void *) i);
4156 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004157 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07004158 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004159 ARM_PSEUDO_kChainingCellInvokePredicted;
Ben Cheng38329f52009-07-07 14:19:20 -07004160 /* handle the codegen later */
4161 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004162 &chainingListByType[kChainingCellInvokePredicted],
Ben Cheng38329f52009-07-07 14:19:20 -07004163 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004164 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004165 case kChainingCellHot:
Ben Chengba4fc8b2009-06-01 13:00:29 -07004166 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004167 ARM_PSEUDO_kChainingCellHot;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004168 /* handle the codegen later */
4169 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004170 &chainingListByType[kChainingCellHot],
Ben Chengba4fc8b2009-06-01 13:00:29 -07004171 (void *) i);
4172 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004173 case kPCReconstruction:
Ben Chengba4fc8b2009-06-01 13:00:29 -07004174 /* Make sure exception handling block is next */
4175 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004176 ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004177 assert (i == cUnit->numBlocks - 2);
4178 handlePCReconstruction(cUnit, &labelList[i+1]);
4179 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004180 case kExceptionHandling:
4181 labelList[i].opCode = kArmPseudoEHBlockLabel;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004182 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07004183 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4184 jitToInterpEntries.dvmJitToInterpPunt),
4185 r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07004186 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004187 }
4188 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004189#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07004190 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07004191 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004192 ARM_PSEUDO_kChainingCellBackwardBranch;
Jeff Hao97319a82009-08-12 16:57:15 -07004193 /* handle the codegen later */
4194 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004195 &chainingListByType[kChainingCellBackwardBranch],
Jeff Hao97319a82009-08-12 16:57:15 -07004196 (void *) i);
4197 break;
4198#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004199 default:
4200 break;
4201 }
4202 continue;
4203 }
Ben Chenge9695e52009-06-16 16:11:47 -07004204
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004205 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07004206
Ben Chengba4fc8b2009-06-01 13:00:29 -07004207 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004208
4209 resetRegPool(cUnit);
4210 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
4211 clobberAllRegs(cUnit);
4212 }
4213
4214 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
4215 resetDefTracking(cUnit);
4216 }
4217
4218 if (mir->dalvikInsn.opCode >= kMirOpFirst) {
Ben Cheng4238ec22009-08-24 16:32:22 -07004219 handleExtendedMIR(cUnit, mir);
4220 continue;
4221 }
4222
Bill Buzbee1465db52009-09-23 17:17:35 -07004223
Ben Chengba4fc8b2009-06-01 13:00:29 -07004224 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
4225 InstructionFormat dalvikFormat =
4226 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004227 ArmLIR *boundaryLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004228 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
Ben Chengccd6c012009-10-15 14:52:45 -07004229 mir->offset,
4230 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
4231 );
Ben Cheng4238ec22009-08-24 16:32:22 -07004232 if (mir->ssaRep) {
4233 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07004234 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07004235 }
4236
Ben Chenge9695e52009-06-16 16:11:47 -07004237 /* Remember the first LIR for this block */
4238 if (headLIR == NULL) {
4239 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07004240 /* Set the first boundaryLIR as a scheduling barrier */
4241 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07004242 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004243
Ben Chengba4fc8b2009-06-01 13:00:29 -07004244 bool notHandled;
4245 /*
4246 * Debugging: screen the opcode first to see if it is in the
4247 * do[-not]-compile list
4248 */
4249 bool singleStepMe =
4250 gDvmJit.includeSelectedOp !=
4251 ((gDvmJit.opList[dalvikOpCode >> 3] &
4252 (1 << (dalvikOpCode & 0x7))) !=
4253 0);
Jeff Hao97319a82009-08-12 16:57:15 -07004254#if defined(WITH_SELF_VERIFICATION)
4255 /* Punt on opcodes we can't replay */
4256 if (selfVerificationPuntOps(dalvikOpCode))
4257 singleStepMe = true;
4258#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004259 if (singleStepMe || cUnit->allSingleStep) {
4260 notHandled = false;
4261 genInterpSingleStep(cUnit, mir);
4262 } else {
4263 opcodeCoverage[dalvikOpCode]++;
4264 switch (dalvikFormat) {
4265 case kFmt10t:
4266 case kFmt20t:
4267 case kFmt30t:
4268 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4269 mir, blockList[i], labelList);
4270 break;
4271 case kFmt10x:
4272 notHandled = handleFmt10x(cUnit, mir);
4273 break;
4274 case kFmt11n:
4275 case kFmt31i:
4276 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4277 break;
4278 case kFmt11x:
4279 notHandled = handleFmt11x(cUnit, mir);
4280 break;
4281 case kFmt12x:
4282 notHandled = handleFmt12x(cUnit, mir);
4283 break;
4284 case kFmt20bc:
4285 notHandled = handleFmt20bc(cUnit, mir);
4286 break;
4287 case kFmt21c:
4288 case kFmt31c:
4289 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4290 break;
4291 case kFmt21h:
4292 notHandled = handleFmt21h(cUnit, mir);
4293 break;
4294 case kFmt21s:
4295 notHandled = handleFmt21s(cUnit, mir);
4296 break;
4297 case kFmt21t:
4298 notHandled = handleFmt21t(cUnit, mir, blockList[i],
4299 labelList);
4300 break;
4301 case kFmt22b:
4302 case kFmt22s:
4303 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4304 break;
4305 case kFmt22c:
4306 notHandled = handleFmt22c(cUnit, mir);
4307 break;
4308 case kFmt22cs:
4309 notHandled = handleFmt22cs(cUnit, mir);
4310 break;
4311 case kFmt22t:
4312 notHandled = handleFmt22t(cUnit, mir, blockList[i],
4313 labelList);
4314 break;
4315 case kFmt22x:
4316 case kFmt32x:
4317 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4318 break;
4319 case kFmt23x:
4320 notHandled = handleFmt23x(cUnit, mir);
4321 break;
4322 case kFmt31t:
4323 notHandled = handleFmt31t(cUnit, mir);
4324 break;
4325 case kFmt3rc:
4326 case kFmt35c:
4327 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4328 labelList);
4329 break;
4330 case kFmt3rms:
4331 case kFmt35ms:
4332 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4333 labelList);
4334 break;
4335 case kFmt3inline:
4336 notHandled = handleFmt3inline(cUnit, mir);
4337 break;
4338 case kFmt51l:
4339 notHandled = handleFmt51l(cUnit, mir);
4340 break;
4341 default:
4342 notHandled = true;
4343 break;
4344 }
4345 }
4346 if (notHandled) {
4347 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4348 mir->offset,
4349 dalvikOpCode, getOpcodeName(dalvikOpCode),
4350 dalvikFormat);
4351 dvmAbort();
4352 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004353 }
4354 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004355
Bill Buzbee1465db52009-09-23 17:17:35 -07004356 if (blockList[i]->blockType == kEntryBlock) {
Ben Cheng4238ec22009-08-24 16:32:22 -07004357 dvmCompilerAppendLIR(cUnit,
4358 (LIR *) cUnit->loopAnalysis->branchToBody);
4359 dvmCompilerAppendLIR(cUnit,
4360 (LIR *) cUnit->loopAnalysis->branchToPCR);
4361 }
4362
4363 if (headLIR) {
4364 /*
4365 * Eliminate redundant loads/stores and delay stores into later
4366 * slots
4367 */
4368 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4369 cUnit->lastLIRInsn);
4370 }
4371
4372gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004373 /*
4374 * Check if the block is terminated due to trace length constraint -
4375 * insert an unconditional branch to the chaining cell.
4376 */
4377 if (blockList[i]->needFallThroughBranch) {
4378 genUnconditionalBranch(cUnit,
4379 &labelList[blockList[i]->fallThrough->id]);
4380 }
4381
Ben Chengba4fc8b2009-06-01 13:00:29 -07004382 }
4383
Ben Chenge9695e52009-06-16 16:11:47 -07004384 /* Handle the chaining cells in predefined order */
Bill Buzbee1465db52009-09-23 17:17:35 -07004385 for (i = 0; i < kChainingCellLast; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004386 size_t j;
4387 int *blockIdList = (int *) chainingListByType[i].elemList;
4388
4389 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4390
4391 /* No chaining cells of this type */
4392 if (cUnit->numChainingCells[i] == 0)
4393 continue;
4394
4395 /* Record the first LIR for a new type of chaining cell */
4396 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4397
4398 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4399 int blockId = blockIdList[j];
4400
4401 /* Align this chaining cell first */
Bill Buzbee1465db52009-09-23 17:17:35 -07004402 newLIR0(cUnit, kArmPseudoPseudoAlign4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004403
4404 /* Insert the pseudo chaining instruction */
4405 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4406
4407
4408 switch (blockList[blockId]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004409 case kChainingCellNormal:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004410 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004411 blockList[blockId]->startOffset);
4412 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004413 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07004414 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004415 blockList[blockId]->containingMethod);
4416 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004417 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07004418 handleInvokePredictedChainingCell(cUnit);
4419 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004420 case kChainingCellHot:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004421 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004422 blockList[blockId]->startOffset);
4423 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004424#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07004425 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07004426 handleBackwardBranchChainingCell(cUnit,
4427 blockList[blockId]->startOffset);
4428 break;
4429#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004430 default:
Bill Buzbee1465db52009-09-23 17:17:35 -07004431 LOGE("Bad blocktype %d", blockList[blockId]->blockType);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004432 dvmAbort();
4433 break;
4434 }
4435 }
4436 }
Ben Chenge9695e52009-06-16 16:11:47 -07004437
4438 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004439}
4440
4441/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004442bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004443{
Ben Chengccd6c012009-10-15 14:52:45 -07004444 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004445
Ben Chengccd6c012009-10-15 14:52:45 -07004446 if (gDvmJit.codeCacheFull) {
4447 return false;
4448 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07004449
Ben Chengccd6c012009-10-15 14:52:45 -07004450 switch (work->kind) {
4451 case kWorkOrderMethod:
4452 res = dvmCompileMethod(work->info, &work->result);
4453 break;
4454 case kWorkOrderTrace:
4455 /* Start compilation with maximally allowed trace length */
4456 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
4457 break;
4458 case kWorkOrderTraceDebug: {
4459 bool oldPrintMe = gDvmJit.printMe;
4460 gDvmJit.printMe = true;
4461 /* Start compilation with maximally allowed trace length */
4462 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
4463 gDvmJit.printMe = oldPrintMe;;
4464 break;
4465 }
4466 default:
4467 res = false;
4468 dvmAbort();
4469 }
4470 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004471}
4472
Ben Chengba4fc8b2009-06-01 13:00:29 -07004473/* Architectural-specific debugging helpers go here */
4474void dvmCompilerArchDump(void)
4475{
4476 /* Print compiled opcode in this VM instance */
4477 int i, start, streak;
4478 char buf[1024];
4479
4480 streak = i = 0;
4481 buf[0] = 0;
4482 while (opcodeCoverage[i] == 0 && i < 256) {
4483 i++;
4484 }
4485 if (i == 256) {
4486 return;
4487 }
4488 for (start = i++, streak = 1; i < 256; i++) {
4489 if (opcodeCoverage[i]) {
4490 streak++;
4491 } else {
4492 if (streak == 1) {
4493 sprintf(buf+strlen(buf), "%x,", start);
4494 } else {
4495 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4496 }
4497 streak = 0;
4498 while (opcodeCoverage[i] == 0 && i < 256) {
4499 i++;
4500 }
4501 if (i < 256) {
4502 streak = 1;
4503 start = i;
4504 }
4505 }
4506 }
4507 if (streak) {
4508 if (streak == 1) {
4509 sprintf(buf+strlen(buf), "%x", start);
4510 } else {
4511 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4512 }
4513 }
4514 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004515 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004516 }
4517}
Ben Chengd7d426a2009-09-22 11:23:36 -07004518
4519/* Common initialization routine for an architecture family */
4520bool dvmCompilerArchInit()
4521{
4522 int i;
4523
Bill Buzbee1465db52009-09-23 17:17:35 -07004524 for (i = 0; i < kArmLast; i++) {
Ben Chengd7d426a2009-09-22 11:23:36 -07004525 if (EncodingMap[i].opCode != i) {
4526 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4527 EncodingMap[i].name, i, EncodingMap[i].opCode);
4528 dvmAbort();
4529 }
4530 }
4531
4532 return compilerArchVariantInit();
4533}