blob: 5dea4311f4cf80b1655ffa672ea858d1fd607a26 [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Bill Buzbee50a6bf22009-07-08 13:08:04 -070017/*
18 * This file contains codegen and support common to all supported
19 * ARM variants. It is included by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 * which combines this common code with specific support found in the
24 * applicable directory below this one.
25 */
26
Ben Cheng4238ec22009-08-24 16:32:22 -070027#include "compiler/Loop.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070028
Ben Chengba4fc8b2009-06-01 13:00:29 -070029/* Array holding the entry offset of each template relative to the first one */
30static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
31
32/* Track exercised opcodes */
33static int opcodeCoverage[256];
34
Jeff Hao97319a82009-08-12 16:57:15 -070035#if defined(WITH_SELF_VERIFICATION)
36/* Prevent certain opcodes from being jitted */
37static inline bool selfVerificationPuntOps(OpCode op)
38{
39 return (op == OP_MONITOR_ENTER || op == OP_MONITOR_EXIT ||
40 op == OP_NEW_INSTANCE || op == OP_NEW_ARRAY);
41}
42
43/*
44 * The following are used to keep compiled loads and stores from modifying
45 * memory during self verification mode.
46 *
47 * Stores do not modify memory. Instead, the address and value pair are stored
48 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
49 * than a word, the word containing the address is loaded first before being
50 * updated.
51 *
52 * Loads check heapSpace first and return data from there if an entry exists.
53 * Otherwise, data is loaded from memory as usual.
54 */
55
56/* Decode contents of heapArgSpace to determine addr to load from */
57static void selfVerificationLoadDecode(HeapArgSpace* heapArgSpace, int* addr)
58{
Bill Buzbee1465db52009-09-23 17:17:35 -070059 int reg = heapArgSpace->regMap & 0xFF;
60 if (!FPREG(reg)) {
61 assert(reg < 16);
62 *addr = heapArgSpace->coreRegs[reg];
63 } else {
64 assert(!DOUBLEREG(reg));
65 *addr = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
Jeff Hao97319a82009-08-12 16:57:15 -070066 }
67}
68
69/* Decode contents of heapArgSpace to determine reg to load into */
70static void selfVerificationLoadDecodeData(HeapArgSpace* heapArgSpace,
71 int data, int reg)
72{
Bill Buzbee1465db52009-09-23 17:17:35 -070073 if (!FPREG(reg)) {
74 assert(reg < 16);
75 heapArgSpace->coreRegs[reg] = data;
76 } else {
77 assert(!DOUBLEREG(reg));
78 heapArgSpace->fpRegs[(reg & FP_REG_MASK)] = data;
Jeff Hao97319a82009-08-12 16:57:15 -070079 }
80}
81
82static void selfVerificationLoad(InterpState* interpState)
83{
84 Thread *self = dvmThreadSelf();
85 ShadowHeap *heapSpacePtr;
86 ShadowSpace *shadowSpace = self->shadowSpace;
87 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
88
89 int addr, data;
90 selfVerificationLoadDecode(heapArgSpace, &addr);
91
92 for (heapSpacePtr = shadowSpace->heapSpace;
93 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
94 if (heapSpacePtr->addr == addr) {
95 data = heapSpacePtr->data;
96 break;
97 }
98 }
99
100 if (heapSpacePtr == shadowSpace->heapSpaceTail)
101 data = *((unsigned int*) addr);
102
Bill Buzbee1465db52009-09-23 17:17:35 -0700103 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Ben Chengd7d426a2009-09-22 11:23:36 -0700104
Bill Buzbee1465db52009-09-23 17:17:35 -0700105 // LOGD("*** HEAP LOAD: Reg:%d Addr: 0x%x Data: 0x%x", reg, addr, data);
Ben Chengd7d426a2009-09-22 11:23:36 -0700106
Jeff Hao97319a82009-08-12 16:57:15 -0700107 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
108}
109
110static void selfVerificationLoadByte(InterpState* interpState)
111{
112 Thread *self = dvmThreadSelf();
113 ShadowHeap *heapSpacePtr;
114 ShadowSpace *shadowSpace = self->shadowSpace;
115 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
116
117 int addr, data;
118 selfVerificationLoadDecode(heapArgSpace, &addr);
119
120 int maskedAddr = addr & 0xFFFFFFFC;
121 int alignment = addr & 0x3;
122
123 for (heapSpacePtr = shadowSpace->heapSpace;
124 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
125 if (heapSpacePtr->addr == maskedAddr) {
126 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
127 data = *((unsigned char*) addr);
128 break;
129 }
130 }
131
132 if (heapSpacePtr == shadowSpace->heapSpaceTail)
133 data = *((unsigned char*) addr);
134
135 //LOGD("*** HEAP LOAD BYTE: Addr: 0x%x Data: 0x%x", addr, data);
136
Bill Buzbee1465db52009-09-23 17:17:35 -0700137 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700138 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
139}
140
141static void selfVerificationLoadHalfword(InterpState* interpState)
142{
143 Thread *self = dvmThreadSelf();
144 ShadowHeap *heapSpacePtr;
145 ShadowSpace *shadowSpace = self->shadowSpace;
146 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
147
148 int addr, data;
149 selfVerificationLoadDecode(heapArgSpace, &addr);
150
151 int maskedAddr = addr & 0xFFFFFFFC;
152 int alignment = addr & 0x2;
153
154 for (heapSpacePtr = shadowSpace->heapSpace;
155 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
156 if (heapSpacePtr->addr == maskedAddr) {
157 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
158 data = *((unsigned short*) addr);
159 break;
160 }
161 }
162
163 if (heapSpacePtr == shadowSpace->heapSpaceTail)
164 data = *((unsigned short*) addr);
165
Bill Buzbee1465db52009-09-23 17:17:35 -0700166 //LOGD("*** HEAP LOAD kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700167
Bill Buzbee1465db52009-09-23 17:17:35 -0700168 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700169 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
170}
171
172static void selfVerificationLoadSignedByte(InterpState* interpState)
173{
174 Thread *self = dvmThreadSelf();
175 ShadowHeap* heapSpacePtr;
176 ShadowSpace* shadowSpace = self->shadowSpace;
177 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
178
179 int addr, data;
180 selfVerificationLoadDecode(heapArgSpace, &addr);
181
182 int maskedAddr = addr & 0xFFFFFFFC;
183 int alignment = addr & 0x3;
184
185 for (heapSpacePtr = shadowSpace->heapSpace;
186 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
187 if (heapSpacePtr->addr == maskedAddr) {
188 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
189 data = *((signed char*) addr);
190 break;
191 }
192 }
193
194 if (heapSpacePtr == shadowSpace->heapSpaceTail)
195 data = *((signed char*) addr);
196
197 //LOGD("*** HEAP LOAD SIGNED BYTE: Addr: 0x%x Data: 0x%x", addr, data);
198
Bill Buzbee1465db52009-09-23 17:17:35 -0700199 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700200 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
201}
202
203static void selfVerificationLoadSignedHalfword(InterpState* interpState)
204{
205 Thread *self = dvmThreadSelf();
206 ShadowHeap* heapSpacePtr;
207 ShadowSpace* shadowSpace = self->shadowSpace;
208 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
209
210 int addr, data;
211 selfVerificationLoadDecode(heapArgSpace, &addr);
212
213 int maskedAddr = addr & 0xFFFFFFFC;
214 int alignment = addr & 0x2;
215
216 for (heapSpacePtr = shadowSpace->heapSpace;
217 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
218 if (heapSpacePtr->addr == maskedAddr) {
219 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
220 data = *((signed short*) addr);
221 break;
222 }
223 }
224
225 if (heapSpacePtr == shadowSpace->heapSpaceTail)
226 data = *((signed short*) addr);
227
Bill Buzbee1465db52009-09-23 17:17:35 -0700228 //LOGD("*** HEAP LOAD SIGNED kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700229
Bill Buzbee1465db52009-09-23 17:17:35 -0700230 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700231 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
232}
233
234static void selfVerificationLoadDoubleword(InterpState* interpState)
235{
236 Thread *self = dvmThreadSelf();
237 ShadowHeap* heapSpacePtr;
238 ShadowSpace* shadowSpace = self->shadowSpace;
239 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
240
241 int addr;
242 selfVerificationLoadDecode(heapArgSpace, &addr);
243
244 int addr2 = addr+4;
245 unsigned int data = *((unsigned int*) addr);
246 unsigned int data2 = *((unsigned int*) addr2);
247
248 for (heapSpacePtr = shadowSpace->heapSpace;
249 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
250 if (heapSpacePtr->addr == addr) {
251 data = heapSpacePtr->data;
252 } else if (heapSpacePtr->addr == addr2) {
253 data2 = heapSpacePtr->data;
254 }
255 }
256
Bill Buzbee1465db52009-09-23 17:17:35 -0700257 // LOGD("*** HEAP LOAD DOUBLEWORD: Addr: 0x%x Data: 0x%x Data2: 0x%x",
Jeff Hao97319a82009-08-12 16:57:15 -0700258 // addr, data, data2);
259
Bill Buzbee1465db52009-09-23 17:17:35 -0700260 int reg = (heapArgSpace->regMap >> 8) & 0xFF;
261 int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700262 selfVerificationLoadDecodeData(heapArgSpace, data, reg);
263 selfVerificationLoadDecodeData(heapArgSpace, data2, reg2);
264}
265
266/* Decode contents of heapArgSpace to determine arguments to store. */
267static void selfVerificationStoreDecode(HeapArgSpace* heapArgSpace,
268 int* value, int reg)
269{
Bill Buzbee1465db52009-09-23 17:17:35 -0700270 if (!FPREG(reg)) {
271 assert(reg < 16);
272 *value = heapArgSpace->coreRegs[reg];
273 } else {
274 assert(!DOUBLEREG(reg));
275 *value = heapArgSpace->fpRegs[(reg & FP_REG_MASK)];
Jeff Hao97319a82009-08-12 16:57:15 -0700276 }
277}
278
279static void selfVerificationStore(InterpState* interpState)
280{
281 Thread *self = dvmThreadSelf();
282 ShadowHeap *heapSpacePtr;
283 ShadowSpace *shadowSpace = self->shadowSpace;
284 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
285
286 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700287 int reg0 = heapArgSpace->regMap & 0xFF;
288 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700289 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
290 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
291
292 //LOGD("*** HEAP STORE: Addr: 0x%x Data: 0x%x", addr, data);
293
294 for (heapSpacePtr = shadowSpace->heapSpace;
295 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
296 if (heapSpacePtr->addr == addr) break;
297 }
298
299 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
300 heapSpacePtr->addr = addr;
301 shadowSpace->heapSpaceTail++;
302 }
303
304 heapSpacePtr->data = data;
305}
306
307static void selfVerificationStoreByte(InterpState* interpState)
308{
309 Thread *self = dvmThreadSelf();
310 ShadowHeap *heapSpacePtr;
311 ShadowSpace *shadowSpace = self->shadowSpace;
312 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
313
314 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700315 int reg0 = heapArgSpace->regMap & 0xFF;
316 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700317 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
318 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
319
320 int maskedAddr = addr & 0xFFFFFFFC;
321 int alignment = addr & 0x3;
322
323 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Data: 0x%x", addr, data);
324
325 for (heapSpacePtr = shadowSpace->heapSpace;
326 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
327 if (heapSpacePtr->addr == maskedAddr) break;
328 }
329
330 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
331 heapSpacePtr->addr = maskedAddr;
332 heapSpacePtr->data = *((unsigned int*) maskedAddr);
333 shadowSpace->heapSpaceTail++;
334 }
335
336 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
337 *((unsigned char*) addr) = (char) data;
338
339 //LOGD("*** HEAP STORE BYTE: Addr: 0x%x Final Data: 0x%x",
340 // addr, heapSpacePtr->data);
341}
342
343static void selfVerificationStoreHalfword(InterpState* interpState)
344{
345 Thread *self = dvmThreadSelf();
346 ShadowHeap *heapSpacePtr;
347 ShadowSpace *shadowSpace = self->shadowSpace;
348 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
349
350 int addr, data;
Bill Buzbee1465db52009-09-23 17:17:35 -0700351 int reg0 = heapArgSpace->regMap & 0xFF;
352 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700353 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
354 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
355
356 int maskedAddr = addr & 0xFFFFFFFC;
357 int alignment = addr & 0x2;
358
Bill Buzbee1465db52009-09-23 17:17:35 -0700359 //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Data: 0x%x", addr, data);
Jeff Hao97319a82009-08-12 16:57:15 -0700360
361 for (heapSpacePtr = shadowSpace->heapSpace;
362 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
363 if (heapSpacePtr->addr == maskedAddr) break;
364 }
365
366 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
367 heapSpacePtr->addr = maskedAddr;
368 heapSpacePtr->data = *((unsigned int*) maskedAddr);
369 shadowSpace->heapSpaceTail++;
370 }
371
372 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
373 *((unsigned short*) addr) = (short) data;
374
Bill Buzbee1465db52009-09-23 17:17:35 -0700375 //LOGD("*** HEAP STORE kHalfWord: Addr: 0x%x Final Data: 0x%x",
Jeff Hao97319a82009-08-12 16:57:15 -0700376 // addr, heapSpacePtr->data);
377}
378
379static void selfVerificationStoreDoubleword(InterpState* interpState)
380{
381 Thread *self = dvmThreadSelf();
382 ShadowHeap *heapSpacePtr;
383 ShadowSpace *shadowSpace = self->shadowSpace;
384 HeapArgSpace *heapArgSpace = &(interpState->heapArgSpace);
385
386 int addr, data, data2;
Bill Buzbee1465db52009-09-23 17:17:35 -0700387 int reg0 = heapArgSpace->regMap & 0xFF;
388 int reg1 = (heapArgSpace->regMap >> 8) & 0xFF;
389 int reg2 = (heapArgSpace->regMap >> 16) & 0xFF;
Jeff Hao97319a82009-08-12 16:57:15 -0700390 selfVerificationStoreDecode(heapArgSpace, &addr, reg0);
391 selfVerificationStoreDecode(heapArgSpace, &data, reg1);
392 selfVerificationStoreDecode(heapArgSpace, &data2, reg2);
393
394 int addr2 = addr+4;
395 bool store1 = false, store2 = false;
396
397 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: 0x%x Data: 0x%x, Data2: 0x%x",
398 // addr, data, data2);
399
400 for (heapSpacePtr = shadowSpace->heapSpace;
401 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
402 if (heapSpacePtr->addr == addr) {
403 heapSpacePtr->data = data;
404 store1 = true;
405 } else if (heapSpacePtr->addr == addr2) {
406 heapSpacePtr->data = data2;
407 store2 = true;
408 }
409 }
410
411 if (!store1) {
412 shadowSpace->heapSpaceTail->addr = addr;
413 shadowSpace->heapSpaceTail->data = data;
414 shadowSpace->heapSpaceTail++;
415 }
416 if (!store2) {
417 shadowSpace->heapSpaceTail->addr = addr2;
418 shadowSpace->heapSpaceTail->data = data2;
419 shadowSpace->heapSpaceTail++;
420 }
421}
422
423/* Common wrapper function for all memory operations */
424static void selfVerificationMemOpWrapper(CompilationUnit *cUnit, int regMap,
425 void* funct)
426{
Bill Buzbee1465db52009-09-23 17:17:35 -0700427 /* push r0 and r7 to give us a foothold */
428 newLIR1(cUnit, kThumbPush, (1 << r0) | (1 << r7));
Jeff Hao97319a82009-08-12 16:57:15 -0700429
Bill Buzbee1465db52009-09-23 17:17:35 -0700430 /* Let the save handler know where the save record is */
431 loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace));
Jeff Hao97319a82009-08-12 16:57:15 -0700432
Bill Buzbee1465db52009-09-23 17:17:35 -0700433 /* Load the regMap and call the save handler [note: handler pops r0/r7] */
434 loadConstant(cUnit, r7, regMap);
435 genDispatchToHandler(cUnit, TEMPLATE_SAVE_STATE);
Jeff Hao97319a82009-08-12 16:57:15 -0700436
Bill Buzbee1465db52009-09-23 17:17:35 -0700437 /* Set function pointer, pass rGLUE and branch */
Jeff Hao97319a82009-08-12 16:57:15 -0700438 loadConstant(cUnit, r1, (int) funct);
Bill Buzbee1465db52009-09-23 17:17:35 -0700439 newLIR2(cUnit, kThumbMovRR, r0, rGLUE);
440 newLIR1(cUnit, kThumbBlxR, r1);
Jeff Hao97319a82009-08-12 16:57:15 -0700441
Bill Buzbee1465db52009-09-23 17:17:35 -0700442 /* Let the recover handler know where coreRegs[0] and restore regs */
443 loadConstant(cUnit, r0, offsetof(InterpState, heapArgSpace) +
444 offsetof(HeapArgSpace, coreRegs));
445 genDispatchToHandler(cUnit, TEMPLATE_RESTORE_STATE);
Jeff Hao97319a82009-08-12 16:57:15 -0700446}
447#endif
448
Ben Chengba4fc8b2009-06-01 13:00:29 -0700449/*
Bill Buzbee1465db52009-09-23 17:17:35 -0700450 * Load a Dalvik register into a physical register. Take care when
451 * using this routine, as it doesn't perform any bookkeeping regarding
452 * register liveness. That is the responsibility of the caller.
453 */
454static void loadValueDirect(CompilationUnit *cUnit, RegLocation rlSrc,
455 int reg1)
456{
457 rlSrc = updateLoc(cUnit, rlSrc); /* Is our value hiding in a live temp? */
458 if (rlSrc.location == kLocPhysReg) {
459 genRegCopy(cUnit, reg1, rlSrc.lowReg);
460 } else if (rlSrc.location == kLocRetval) {
461 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), reg1);
462 } else {
463 assert(rlSrc.location == kLocDalvikFrame);
464 loadWordDisp(cUnit, rFP, sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
465 reg1);
466 }
467}
468
469/*
470 * Similar to loadValueDirect, but clobbers and allocates the target
471 * register. Should be used when loading to a fixed register (for example,
472 * loading arguments to an out of line call.
473 */
474static void loadValueDirectFixed(CompilationUnit *cUnit, RegLocation rlSrc,
475 int reg1)
476{
477 clobberReg(cUnit, reg1);
478 markRegInUse(cUnit, reg1);
479 loadValueDirect(cUnit, rlSrc, reg1);
480}
481
482/*
483 * Load a Dalvik register pair into a physical register[s]. Take care when
484 * using this routine, as it doesn't perform any bookkeeping regarding
485 * register liveness. That is the responsibility of the caller.
486 */
487static void loadValueDirectWide(CompilationUnit *cUnit, RegLocation rlSrc,
488 int regLo, int regHi)
489{
490 rlSrc = updateLocWide(cUnit, rlSrc);
491 if (rlSrc.location == kLocPhysReg) {
492 genRegCopyWide(cUnit, regLo, regHi, rlSrc.lowReg, rlSrc.highReg);
493 } else if (rlSrc.location == kLocRetval) {
494 loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
495 regLo, regHi, false, INVALID_SREG);
496 } else {
497 assert(rlSrc.location == kLocDalvikFrame);
498 loadBaseDispWide(cUnit, NULL, rFP,
499 sReg2vReg(cUnit, rlSrc.sRegLow) << 2,
500 regLo, regHi, false, INVALID_SREG);
501 }
502}
503
504/*
505 * Similar to loadValueDirect, but clobbers and allocates the target
506 * registers. Should be used when loading to a fixed registers (for example,
507 * loading arguments to an out of line call.
508 */
509static void loadValueDirectWideFixed(CompilationUnit *cUnit, RegLocation rlSrc,
510 int regLo, int regHi)
511{
512 clobberReg(cUnit, regLo);
513 clobberReg(cUnit, regHi);
514 markRegInUse(cUnit, regLo);
515 markRegInUse(cUnit, regHi);
516 loadValueDirectWide(cUnit, rlSrc, regLo, regHi);
517}
518
519static RegLocation loadValue(CompilationUnit *cUnit, RegLocation rlSrc,
520 RegisterClass opKind)
521{
522 RegisterInfo *pReg;
523 rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
524 if (rlSrc.location == kLocDalvikFrame) {
525 loadValueDirect(cUnit, rlSrc, rlSrc.lowReg);
526 rlSrc.location = kLocPhysReg;
527 markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
528 } else if (rlSrc.location == kLocRetval) {
529 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, retval), rlSrc.lowReg);
530 rlSrc.location = kLocPhysReg;
531 clobberReg(cUnit, rlSrc.lowReg);
532 }
533 return rlSrc;
534}
535
536static RegLocation loadValueWide(CompilationUnit *cUnit, RegLocation rlSrc,
537 RegisterClass opKind)
538{
539 RegisterInfo *pRegLo;
540 RegisterInfo *pRegHi;
541 assert(rlSrc.wide);
542 rlSrc = evalLoc(cUnit, rlSrc, opKind, false);
543 if (rlSrc.location == kLocDalvikFrame) {
544 loadValueDirectWide(cUnit, rlSrc, rlSrc.lowReg, rlSrc.highReg);
545 rlSrc.location = kLocPhysReg;
546 markRegLive(cUnit, rlSrc.lowReg, rlSrc.sRegLow);
547 markRegLive(cUnit, rlSrc.highReg, hiSReg(rlSrc.sRegLow));
548 } else if (rlSrc.location == kLocRetval) {
549 loadBaseDispWide(cUnit, NULL, rGLUE, offsetof(InterpState, retval),
550 rlSrc.lowReg, rlSrc.highReg, false, INVALID_SREG);
551 rlSrc.location = kLocPhysReg;
552 clobberReg(cUnit, rlSrc.lowReg);
553 clobberReg(cUnit, rlSrc.highReg);
554 }
555 return rlSrc;
556}
557
558static void storeValue(CompilationUnit *cUnit, RegLocation rlDest,
559 RegLocation rlSrc)
560{
561 RegisterInfo *pRegLo;
562 LIR *defStart;
563 LIR *defEnd;
564 assert(!rlDest.wide);
565 assert(!rlSrc.wide);
566 killNullCheckedLocation(cUnit, rlDest);
567 rlSrc = updateLoc(cUnit, rlSrc);
568 rlDest = updateLoc(cUnit, rlDest);
569 if (rlSrc.location == kLocPhysReg) {
570 if (isLive(cUnit, rlSrc.lowReg) || (rlDest.location == kLocPhysReg)) {
571 // Src is live or Dest has assigned reg.
572 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
573 genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
574 } else {
575 // Just re-assign the registers. Dest gets Src's regs
576 rlDest.lowReg = rlSrc.lowReg;
577 clobberReg(cUnit, rlSrc.lowReg);
578 }
579 } else {
580 // Load Src either into promoted Dest or temps allocated for Dest
581 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
582 loadValueDirect(cUnit, rlSrc, rlDest.lowReg);
583 }
584
585 // Dest is now live and dirty (until/if we flush it to home location)
586 markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
587 markRegDirty(cUnit, rlDest.lowReg);
588
589
590 if (rlDest.location == kLocRetval) {
591 storeBaseDisp(cUnit, rGLUE, offsetof(InterpState, retval),
592 rlDest.lowReg, kWord);
593 clobberReg(cUnit, rlDest.lowReg);
594 } else {
595 resetDefLoc(cUnit, rlDest);
596 if (liveOut(cUnit, rlDest.sRegLow)) {
597 defStart = (LIR *)cUnit->lastLIRInsn;
598 int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
599 storeBaseDisp(cUnit, rFP, vReg << 2, rlDest.lowReg, kWord);
600 markRegClean(cUnit, rlDest.lowReg);
601 defEnd = (LIR *)cUnit->lastLIRInsn;
602 markDef(cUnit, rlDest, defStart, defEnd);
603 }
604 }
605}
606
607static void storeValueWide(CompilationUnit *cUnit, RegLocation rlDest,
608 RegLocation rlSrc)
609{
610 RegisterInfo *pRegLo;
611 RegisterInfo *pRegHi;
612 LIR *defStart;
613 LIR *defEnd;
614 bool srcFP = FPREG(rlSrc.lowReg) && FPREG(rlSrc.highReg);
615 assert(FPREG(rlSrc.lowReg)==FPREG(rlSrc.highReg));
616 assert(rlDest.wide);
617 assert(rlSrc.wide);
618 killNullCheckedLocation(cUnit, rlDest);
619 if (rlSrc.location == kLocPhysReg) {
620 if (isLive(cUnit, rlSrc.lowReg) || isLive(cUnit, rlSrc.highReg) ||
621 (rlDest.location == kLocPhysReg)) {
622 // Src is live or Dest has assigned reg.
623 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
624 genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
625 rlSrc.lowReg, rlSrc.highReg);
626 } else {
627 // Just re-assign the registers. Dest gets Src's regs
628 rlDest.lowReg = rlSrc.lowReg;
629 rlDest.highReg = rlSrc.highReg;
630 clobberReg(cUnit, rlSrc.lowReg);
631 clobberReg(cUnit, rlSrc.highReg);
632 }
633 } else {
634 // Load Src either into promoted Dest or temps allocated for Dest
635 rlDest = evalLoc(cUnit, rlDest, kAnyReg, false);
636 loadValueDirectWide(cUnit, rlSrc, rlDest.lowReg,
637 rlDest.highReg);
638 }
639
640 // Dest is now live and dirty (until/if we flush it to home location)
641 markRegLive(cUnit, rlDest.lowReg, rlDest.sRegLow);
642 markRegLive(cUnit, rlDest.highReg, hiSReg(rlDest.sRegLow));
643 markRegDirty(cUnit, rlDest.lowReg);
644 markRegDirty(cUnit, rlDest.highReg);
645 markRegPair(cUnit, rlDest.lowReg, rlDest.highReg);
646
647
648 if (rlDest.location == kLocRetval) {
649 storeBaseDispWide(cUnit, rGLUE, offsetof(InterpState, retval),
650 rlDest.lowReg, rlDest.highReg);
651 clobberReg(cUnit, rlDest.lowReg);
652 clobberReg(cUnit, rlDest.highReg);
653 } else {
654 resetDefLocWide(cUnit, rlDest);
655 if (liveOut(cUnit, rlDest.sRegLow) ||
656 liveOut(cUnit, hiSReg(rlDest.sRegLow))) {
657 defStart = (LIR *)cUnit->lastLIRInsn;
658 int vReg = sReg2vReg(cUnit, rlDest.sRegLow);
659 assert((vReg+1) == sReg2vReg(cUnit, hiSReg(rlDest.sRegLow)));
660 storeBaseDispWide(cUnit, rFP, vReg << 2, rlDest.lowReg,
661 rlDest.highReg);
662 markRegClean(cUnit, rlDest.lowReg);
663 markRegClean(cUnit, rlDest.highReg);
664 defEnd = (LIR *)cUnit->lastLIRInsn;
665 markDefWide(cUnit, rlDest, defStart, defEnd);
666 }
667 }
668}
669
670/*
671 * Load an immediate value into a fixed or temp register. Target
672 * register is clobbered, and marked inUse.
673 */
674static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
675{
676 if (isTemp(cUnit, rDest)) {
677 clobberReg(cUnit, rDest);
678 markRegInUse(cUnit, rDest);
679 }
680 return loadConstantValue(cUnit, rDest, value);
681}
682
683/*
Ben Chengd7d426a2009-09-22 11:23:36 -0700684 * Mark load/store instructions that access Dalvik registers through rFP +
685 * offset.
686 */
687static void annotateDalvikRegAccess(ArmLIR *lir, int regId, bool isLoad)
688{
689 if (isLoad) {
690 lir->useMask |= ENCODE_DALVIK_REG;
691 } else {
692 lir->defMask |= ENCODE_DALVIK_REG;
693 }
694
695 /*
696 * Store the Dalvik register id in aliasInfo. Mark he MSB if it is a 64-bit
697 * access.
698 */
699 lir->aliasInfo = regId;
700 if (DOUBLEREG(lir->operands[0])) {
701 lir->aliasInfo |= 0x80000000;
702 }
703}
704
705/*
706 * Decode the register id and mark the corresponding bit(s).
707 */
708static inline void setupRegMask(u8 *mask, int reg)
709{
710 u8 seed;
711 int shift;
712 int regId = reg & 0x1f;
713
714 /*
715 * Each double register is equal to a pair of single-precision FP registers
716 */
717 seed = DOUBLEREG(reg) ? 3 : 1;
718 /* FP register starts at bit position 16 */
719 shift = FPREG(reg) ? kFPReg0 : 0;
720 /* Expand the double register id into single offset */
721 shift += regId;
722 *mask |= seed << shift;
723}
724
725/*
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700726 * Set up the proper fields in the resource mask
727 */
728static void setupResourceMasks(ArmLIR *lir)
729{
730 int opCode = lir->opCode;
731 int flags;
732
733 if (opCode <= 0) {
734 lir->useMask = lir->defMask = 0;
735 return;
736 }
737
738 flags = EncodingMap[lir->opCode].flags;
739
740 /* Set up the mask for resources that are updated */
741 if (flags & IS_BRANCH) {
742 lir->defMask |= ENCODE_REG_PC;
Ben Chengd7d426a2009-09-22 11:23:36 -0700743 lir->useMask |= ENCODE_REG_PC;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700744 }
745
746 if (flags & REG_DEF0) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700747 setupRegMask(&lir->defMask, lir->operands[0]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700748 }
749
750 if (flags & REG_DEF1) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700751 setupRegMask(&lir->defMask, lir->operands[1]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700752 }
753
754 if (flags & REG_DEF_SP) {
755 lir->defMask |= ENCODE_REG_SP;
756 }
757
Ben Chengd7d426a2009-09-22 11:23:36 -0700758 if (flags & REG_DEF_SP) {
759 lir->defMask |= ENCODE_REG_LR;
760 }
761
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700762 if (flags & REG_DEF_LIST0) {
763 lir->defMask |= ENCODE_REG_LIST(lir->operands[0]);
764 }
765
766 if (flags & REG_DEF_LIST1) {
767 lir->defMask |= ENCODE_REG_LIST(lir->operands[1]);
768 }
769
770 if (flags & SETS_CCODES) {
771 lir->defMask |= ENCODE_CCODE;
772 }
773
774 /* Conservatively treat the IT block */
775 if (flags & IS_IT) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700776 lir->defMask = ENCODE_ALL;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700777 }
778
779 /* Set up the mask for resources that are used */
780 if (flags & IS_BRANCH) {
781 lir->useMask |= ENCODE_REG_PC;
782 }
783
Bill Buzbee1465db52009-09-23 17:17:35 -0700784 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700785 int i;
786
Bill Buzbee1465db52009-09-23 17:17:35 -0700787 for (i = 0; i < 4; i++) {
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700788 if (flags & (1 << (kRegUse0 + i))) {
Ben Chengd7d426a2009-09-22 11:23:36 -0700789 setupRegMask(&lir->useMask, lir->operands[i]);
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700790 }
791 }
792 }
793
794 if (flags & REG_USE_PC) {
795 lir->useMask |= ENCODE_REG_PC;
796 }
797
798 if (flags & REG_USE_SP) {
799 lir->useMask |= ENCODE_REG_SP;
800 }
801
802 if (flags & REG_USE_LIST0) {
803 lir->useMask |= ENCODE_REG_LIST(lir->operands[0]);
804 }
805
806 if (flags & REG_USE_LIST1) {
807 lir->useMask |= ENCODE_REG_LIST(lir->operands[1]);
808 }
809
810 if (flags & USES_CCODES) {
811 lir->useMask |= ENCODE_CCODE;
812 }
813}
814
815/*
Bill Buzbee270c1d62009-08-13 16:58:07 -0700816 * The following are building blocks to construct low-level IRs with 0 - 4
Ben Chengba4fc8b2009-06-01 13:00:29 -0700817 * operands.
818 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700819static ArmLIR *newLIR0(CompilationUnit *cUnit, ArmOpCode opCode)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700820{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700821 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700822 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700823 insn->opCode = opCode;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700824 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700825 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
826 return insn;
827}
828
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700829static ArmLIR *newLIR1(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700830 int dest)
831{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700832 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700833 assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700834 insn->opCode = opCode;
835 insn->operands[0] = dest;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700836 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700837 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
838 return insn;
839}
840
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700841static ArmLIR *newLIR2(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700842 int dest, int src1)
843{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700844 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chenge9695e52009-06-16 16:11:47 -0700845 assert(isPseudoOpCode(opCode) ||
846 (EncodingMap[opCode].flags & IS_BINARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847 insn->opCode = opCode;
848 insn->operands[0] = dest;
849 insn->operands[1] = src1;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700850 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700851 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
852 return insn;
853}
854
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700855static ArmLIR *newLIR3(CompilationUnit *cUnit, ArmOpCode opCode,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700856 int dest, int src1, int src2)
857{
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700858 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700859 if (!(EncodingMap[opCode].flags & IS_TERTIARY_OP)) {
860 LOGE("Bad LIR3: %s[%d]",EncodingMap[opCode].name,opCode);
861 }
Ben Chenge9695e52009-06-16 16:11:47 -0700862 assert(isPseudoOpCode(opCode) ||
863 (EncodingMap[opCode].flags & IS_TERTIARY_OP));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700864 insn->opCode = opCode;
865 insn->operands[0] = dest;
866 insn->operands[1] = src1;
867 insn->operands[2] = src2;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700868 setupResourceMasks(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700869 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
870 return insn;
871}
872
Bill Buzbee270c1d62009-08-13 16:58:07 -0700873static ArmLIR *newLIR4(CompilationUnit *cUnit, ArmOpCode opCode,
874 int dest, int src1, int src2, int info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700875{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700876 ArmLIR *insn = dvmCompilerNew(sizeof(ArmLIR), true);
877 assert(isPseudoOpCode(opCode) ||
878 (EncodingMap[opCode].flags & IS_QUAD_OP));
879 insn->opCode = opCode;
880 insn->operands[0] = dest;
881 insn->operands[1] = src1;
882 insn->operands[2] = src2;
883 insn->operands[3] = info;
Ben Chengdcf3e5d2009-09-11 13:42:05 -0700884 setupResourceMasks(insn);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700885 dvmCompilerAppendLIR(cUnit, (LIR *) insn);
886 return insn;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700887}
888
Ben Chengba4fc8b2009-06-01 13:00:29 -0700889/*
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700890 * If the next instruction is a move-result or move-result-long,
Bill Buzbee1465db52009-09-23 17:17:35 -0700891 * return the target Dalvik sReg[s] and convert the next to a
892 * nop. Otherwise, return INVALID_SREG. Used to optimize method inlining.
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700893 */
Bill Buzbee1465db52009-09-23 17:17:35 -0700894static RegLocation inlinedTarget(CompilationUnit *cUnit, MIR *mir,
895 bool fpHint)
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700896{
897 if (mir->next &&
898 ((mir->next->dalvikInsn.opCode == OP_MOVE_RESULT) ||
Bill Buzbee1465db52009-09-23 17:17:35 -0700899 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_OBJECT))) {
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700900 mir->next->dalvikInsn.opCode = OP_NOP;
Bill Buzbee1465db52009-09-23 17:17:35 -0700901 return getDestLoc(cUnit, mir->next, 0);
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700902 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700903 RegLocation res = LOC_DALVIK_RETURN_VAL;
904 res.fp = fpHint;
905 return res;
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700906 }
907}
908
Bill Buzbee1465db52009-09-23 17:17:35 -0700909static RegLocation inlinedTargetWide(CompilationUnit *cUnit, MIR *mir,
910 bool fpHint)
911{
912 if (mir->next &&
913 (mir->next->dalvikInsn.opCode == OP_MOVE_RESULT_WIDE)) {
914 mir->next->dalvikInsn.opCode = OP_NOP;
915 return getDestLocWide(cUnit, mir->next, 0, 1);
916 } else {
917 RegLocation res = LOC_DALVIK_RETURN_VAL_WIDE;
918 res.fp = fpHint;
919 return res;
920 }
921}
Bill Buzbeea4a7f072009-08-27 13:58:09 -0700922
923/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700924 * The following are building blocks to insert constants into the pool or
925 * instruction streams.
926 */
927
928/* Add a 32-bit constant either in the constant pool or mixed with code */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700929static ArmLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700930{
931 /* Add the constant to the literal pool */
932 if (!inPlace) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700933 ArmLIR *newValue = dvmCompilerNew(sizeof(ArmLIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700934 newValue->operands[0] = value;
935 newValue->generic.next = cUnit->wordList;
936 cUnit->wordList = (LIR *) newValue;
937 return newValue;
938 } else {
939 /* Add the constant in the middle of code stream */
Bill Buzbee1465db52009-09-23 17:17:35 -0700940 newLIR1(cUnit, kArm16BitData, (value & 0xffff));
941 newLIR1(cUnit, kArm16BitData, (value >> 16));
Ben Chengba4fc8b2009-06-01 13:00:29 -0700942 }
943 return NULL;
944}
945
946/*
947 * Search the existing constants in the literal pool for an exact or close match
948 * within specified delta (greater or equal to 0).
949 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700950static ArmLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700951 unsigned int delta)
952{
953 LIR *dataTarget = cUnit->wordList;
954 while (dataTarget) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700955 if (((unsigned) (value - ((ArmLIR *) dataTarget)->operands[0])) <=
Ben Chengba4fc8b2009-06-01 13:00:29 -0700956 delta)
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700957 return (ArmLIR *) dataTarget;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700958 dataTarget = dataTarget->next;
959 }
960 return NULL;
961}
962
Ben Chengba4fc8b2009-06-01 13:00:29 -0700963/* Create the PC reconstruction slot if not already done */
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700964static inline ArmLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
965 ArmLIR *branch,
966 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700967{
968 /* Set up the place holder to reconstruct this Dalvik PC */
969 if (pcrLabel == NULL) {
970 int dPC = (int) (cUnit->method->insns + dOffset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -0700971 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700972 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700973 pcrLabel->operands[0] = dPC;
974 pcrLabel->operands[1] = dOffset;
975 /* Insert the place holder to the growable list */
976 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
977 }
978 /* Branch to the PC reconstruction code */
979 branch->generic.target = (LIR *) pcrLabel;
980 return pcrLabel;
981}
982
Ben Chengba4fc8b2009-06-01 13:00:29 -0700983
984/*
985 * Perform a "reg cmp reg" operation and jump to the PCR region if condition
986 * satisfies.
987 */
Ben Cheng0fd31e42009-09-03 14:40:16 -0700988static inline ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
989 ArmConditionCode cond,
990 int reg1, int reg2, int dOffset,
991 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700992{
Bill Buzbee270c1d62009-08-13 16:58:07 -0700993 ArmLIR *res;
Bill Buzbee1465db52009-09-23 17:17:35 -0700994 res = opRegReg(cUnit, kOpCmp, reg1, reg2);
Ben Cheng4f489172009-09-27 17:08:35 -0700995 ArmLIR *branch = opCondBranch(cUnit, cond);
Bill Buzbee270c1d62009-08-13 16:58:07 -0700996 genCheckCommon(cUnit, dOffset, branch, pcrLabel);
997 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700998}
999
Ben Chenge9695e52009-06-16 16:11:47 -07001000/*
Bill Buzbee1465db52009-09-23 17:17:35 -07001001 * Perform null-check on a register. sReg is the ssa register being checked,
Ben Chenge9695e52009-06-16 16:11:47 -07001002 * and mReg is the machine register holding the actual value. If internal state
Bill Buzbee1465db52009-09-23 17:17:35 -07001003 * indicates that sReg has been checked before the check request is ignored.
Ben Chenge9695e52009-06-16 16:11:47 -07001004 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001005static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001006 int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001007{
Ben Chenge9695e52009-06-16 16:11:47 -07001008 /* This particular Dalvik register has been null-checked */
Bill Buzbee1465db52009-09-23 17:17:35 -07001009 if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
Ben Chenge9695e52009-06-16 16:11:47 -07001010 return pcrLabel;
1011 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001012 dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg);
1013 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
Ben Chenge9695e52009-06-16 16:11:47 -07001014}
1015
1016/*
1017 * Perform zero-check on a register. Similar to genNullCheck but the value being
1018 * checked does not have a corresponding Dalvik register.
1019 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001020static ArmLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
1021 int dOffset, ArmLIR *pcrLabel)
Ben Chenge9695e52009-06-16 16:11:47 -07001022{
Bill Buzbee1465db52009-09-23 17:17:35 -07001023 return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001024}
1025
1026/* Perform bound check on two registers */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001027static ArmLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
1028 int rBound, int dOffset, ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001029{
Bill Buzbee1465db52009-09-23 17:17:35 -07001030 return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001031 pcrLabel);
1032}
1033
1034/* Generate a unconditional branch to go to the interpreter */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001035static inline ArmLIR *genTrap(CompilationUnit *cUnit, int dOffset,
1036 ArmLIR *pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001037{
Bill Buzbee1465db52009-09-23 17:17:35 -07001038 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001039 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
1040}
1041
1042/* Load a wide field from an object instance */
1043static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
1044{
1045 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001046 RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
1047 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
1048 RegLocation rlResult;
1049 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1050 int regPtr = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001051
Bill Buzbee1465db52009-09-23 17:17:35 -07001052 assert(rlDest.wide);
Ben Chenge9695e52009-06-16 16:11:47 -07001053
Bill Buzbee1465db52009-09-23 17:17:35 -07001054 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1055 NULL);/* null object? */
1056 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
1057 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Jeff Hao97319a82009-08-12 16:57:15 -07001058#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001059 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07001060#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001061 int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001062 selfVerificationMemOpWrapper(cUnit, regMap,
1063 &selfVerificationLoadDoubleword);
Jeff Hao97319a82009-08-12 16:57:15 -07001064#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001065 freeTemp(cUnit, regPtr);
1066 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001067}
1068
1069/* Store a wide field to an object instance */
1070static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
1071{
1072 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001073 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1074 RegLocation rlObj = getSrcLoc(cUnit, mir, 2);
1075 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1076 int regPtr;
1077 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1078 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1079 NULL);/* null object? */
1080 regPtr = allocTemp(cUnit);
1081 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001082#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001083 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07001084#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001085 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001086 selfVerificationMemOpWrapper(cUnit, regMap,
1087 &selfVerificationStoreDoubleword);
1088#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001089 freeTemp(cUnit, regPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001090}
1091
1092/*
1093 * Load a field from an object instance
1094 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001095 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001096static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001097 int fieldOffset)
1098{
Bill Buzbee1465db52009-09-23 17:17:35 -07001099 int regPtr;
1100 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001101 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001102 RegLocation rlObj = getSrcLoc(cUnit, mir, 0);
1103 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
1104 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1105 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Jeff Hao97319a82009-08-12 16:57:15 -07001106#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001107 loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
1108 size, true, rlObj.sRegLow);
Jeff Hao97319a82009-08-12 16:57:15 -07001109#else
Bill Buzbee1465db52009-09-23 17:17:35 -07001110 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1111 NULL);/* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -07001112 /* Combine address and offset */
Bill Buzbee1465db52009-09-23 17:17:35 -07001113 regPtr = allocTemp(cUnit);
1114 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001115
Bill Buzbee1465db52009-09-23 17:17:35 -07001116 int regMap = rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001117 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
Bill Buzbee1465db52009-09-23 17:17:35 -07001118 freeTemp(cUnit, regPtr);
Jeff Hao97319a82009-08-12 16:57:15 -07001119#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07001120 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001121}
1122
1123/*
1124 * Store a field to an object instance
1125 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001126 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001127static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001128 int fieldOffset)
1129{
1130 DecodedInstruction *dInsn = &mir->dalvikInsn;
Bill Buzbee1465db52009-09-23 17:17:35 -07001131 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
1132 RegLocation rlObj = getSrcLoc(cUnit, mir, 1);
1133 rlObj = loadValue(cUnit, rlObj, kCoreReg);
1134 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1135 int regPtr;
1136 genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
1137 NULL);/* null object? */
Jeff Hao97319a82009-08-12 16:57:15 -07001138#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001139 storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
Jeff Hao97319a82009-08-12 16:57:15 -07001140#else
1141 /* Combine address and offset */
Bill Buzbee1465db52009-09-23 17:17:35 -07001142 regPtr = allocTemp(cUnit);
1143 opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07001144
Bill Buzbee1465db52009-09-23 17:17:35 -07001145 int regMap = rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001146 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
Jeff Hao97319a82009-08-12 16:57:15 -07001147#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001148}
1149
1150
Ben Chengba4fc8b2009-06-01 13:00:29 -07001151/*
1152 * Generate array load
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001154static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
Bill Buzbee1465db52009-09-23 17:17:35 -07001155 RegLocation rlArray, RegLocation rlIndex,
1156 RegLocation rlDest, int scale)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001157{
1158 int lenOffset = offsetof(ArrayObject, length);
1159 int dataOffset = offsetof(ArrayObject, contents);
Bill Buzbee1465db52009-09-23 17:17:35 -07001160 RegLocation rlResult;
1161 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1162 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
1163 int regPtr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001164
1165 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001166 ArmLIR * pcrLabel = NULL;
1167
1168 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001169 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
1170 rlArray.lowReg, mir->offset, NULL);
Ben Cheng4238ec22009-08-24 16:32:22 -07001171 }
1172
Bill Buzbee1465db52009-09-23 17:17:35 -07001173 regPtr = allocTemp(cUnit);
1174
Ben Cheng4238ec22009-08-24 16:32:22 -07001175 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001176 int regLen = allocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07001177 /* Get len */
Bill Buzbee1465db52009-09-23 17:17:35 -07001178 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1179 /* regPtr -> array data */
1180 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
1181 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
1182 pcrLabel);
1183 freeTemp(cUnit, regLen);
Ben Cheng4238ec22009-08-24 16:32:22 -07001184 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001185 /* regPtr -> array data */
1186 opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -07001187 }
Jeff Hao97319a82009-08-12 16:57:15 -07001188#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001189 if ((size == kLong) || (size == kDouble)) {
1190 if (scale) {
1191 int rNewIndex = allocTemp(cUnit);
1192 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1193 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1194 freeTemp(cUnit, rNewIndex);
1195 } else {
1196 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1197 }
1198 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1199 loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
1200 freeTemp(cUnit, regPtr);
1201 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001202 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001203 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1204 loadBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlResult.lowReg,
1205 scale, size);
1206 freeTemp(cUnit, regPtr);
1207 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001208 }
Jeff Hao97319a82009-08-12 16:57:15 -07001209#else
Bill Buzbee270c1d62009-08-13 16:58:07 -07001210 //TODO: probably want to move this into loadBaseIndexed
1211 void *funct = NULL;
1212 switch(size) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001213 case kLong:
1214 case kDouble:
Jeff Hao97319a82009-08-12 16:57:15 -07001215 funct = (void*) &selfVerificationLoadDoubleword;
1216 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001217 case kWord:
Jeff Hao97319a82009-08-12 16:57:15 -07001218 funct = (void*) &selfVerificationLoad;
1219 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001220 case kUnsignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001221 funct = (void*) &selfVerificationLoadHalfword;
1222 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001223 case kSignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001224 funct = (void*) &selfVerificationLoadSignedHalfword;
1225 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001226 case kUnsignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001227 funct = (void*) &selfVerificationLoadByte;
1228 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001229 case kSignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001230 funct = (void*) &selfVerificationLoadSignedByte;
1231 break;
1232 default:
1233 assert(0);
1234 dvmAbort();
Jeff Hao97319a82009-08-12 16:57:15 -07001235 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001236 /* Combine address and index */
Bill Buzbee1465db52009-09-23 17:17:35 -07001237 if (scale) {
1238 int regTmp = allocTemp(cUnit);
1239 opRegRegImm(cUnit, kOpLsl, regTmp, rlIndex.lowReg, scale);
1240 opRegReg(cUnit, kOpAdd, regPtr, regTmp);
1241 freeTemp(cUnit, regTmp);
1242 } else {
1243 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1244 }
Jeff Hao97319a82009-08-12 16:57:15 -07001245
Bill Buzbee1465db52009-09-23 17:17:35 -07001246 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
1247 int regMap = rlResult.highReg << 16 | rlResult.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001248 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1249
Bill Buzbee1465db52009-09-23 17:17:35 -07001250 freeTemp(cUnit, regPtr);
1251 if ((size == kLong) || (size == kDouble))
1252 storeValueWide(cUnit, rlDest, rlResult);
Jeff Hao97319a82009-08-12 16:57:15 -07001253 else
Bill Buzbee1465db52009-09-23 17:17:35 -07001254 storeValue(cUnit, rlDest, rlResult);
Jeff Hao97319a82009-08-12 16:57:15 -07001255#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001256}
1257
Ben Chengba4fc8b2009-06-01 13:00:29 -07001258/*
1259 * Generate array store
1260 *
Ben Chengba4fc8b2009-06-01 13:00:29 -07001261 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001262static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
Bill Buzbee1465db52009-09-23 17:17:35 -07001263 RegLocation rlArray, RegLocation rlIndex,
1264 RegLocation rlSrc, int scale)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001265{
1266 int lenOffset = offsetof(ArrayObject, length);
1267 int dataOffset = offsetof(ArrayObject, contents);
1268
Bill Buzbee1465db52009-09-23 17:17:35 -07001269 int regPtr;
1270 rlArray = loadValue(cUnit, rlArray, kCoreReg);
1271 rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001272
Bill Buzbee1465db52009-09-23 17:17:35 -07001273 if (isTemp(cUnit, rlArray.lowReg)) {
1274 clobberReg(cUnit, rlArray.lowReg);
1275 regPtr = rlArray.lowReg;
1276 } else {
1277 regPtr = allocTemp(cUnit);
1278 genRegCopy(cUnit, regPtr, rlArray.lowReg);
1279 }
Ben Chenge9695e52009-06-16 16:11:47 -07001280
Ben Cheng1efc9c52009-06-08 18:25:27 -07001281 /* null object? */
Ben Cheng4238ec22009-08-24 16:32:22 -07001282 ArmLIR * pcrLabel = NULL;
1283
1284 if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001285 pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
1286 mir->offset, NULL);
Ben Cheng4238ec22009-08-24 16:32:22 -07001287 }
1288
1289 if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001290 int regLen = allocTemp(cUnit);
1291 //NOTE: max live temps(4) here.
Ben Cheng4238ec22009-08-24 16:32:22 -07001292 /* Get len */
Bill Buzbee1465db52009-09-23 17:17:35 -07001293 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
1294 /* regPtr -> array data */
1295 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
1296 genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
1297 pcrLabel);
1298 freeTemp(cUnit, regLen);
Ben Cheng4238ec22009-08-24 16:32:22 -07001299 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001300 /* regPtr -> array data */
1301 opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -07001302 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001303 /* at this point, regPtr points to array, 2 live temps */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001304#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07001305 if ((size == kLong) || (size == kDouble)) {
1306 //TODO: need specific wide routine that can handle fp regs
1307 if (scale) {
1308 int rNewIndex = allocTemp(cUnit);
1309 opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
1310 opRegReg(cUnit, kOpAdd, regPtr, rNewIndex);
1311 freeTemp(cUnit, rNewIndex);
1312 } else {
1313 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
1314 }
1315 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1316 storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
1317 freeTemp(cUnit, regPtr);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001318 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001319 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1320 storeBaseIndexed(cUnit, regPtr, rlIndex.lowReg, rlSrc.lowReg,
1321 scale, size);
Bill Buzbee270c1d62009-08-13 16:58:07 -07001322 }
1323#else
1324 //TODO: probably want to move this into storeBaseIndexed
1325 void *funct = NULL;
1326 switch(size) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001327 case kLong:
1328 case kDouble:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001329 funct = (void*) &selfVerificationStoreDoubleword;
1330 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001331 case kWord:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001332 funct = (void*) &selfVerificationStore;
1333 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001334 case kSignedHalf:
1335 case kUnsignedHalf:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001336 funct = (void*) &selfVerificationStoreHalfword;
1337 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07001338 case kSignedByte:
1339 case kUnsignedByte:
Bill Buzbee270c1d62009-08-13 16:58:07 -07001340 funct = (void*) &selfVerificationStoreByte;
1341 break;
1342 default:
1343 assert(0);
1344 dvmAbort();
1345 }
1346
Bill Buzbee1465db52009-09-23 17:17:35 -07001347 if (scale) {
1348 int regTmpIndex = allocTemp(cUnit);
1349 // 3 live temps
1350 opRegRegImm(cUnit, kOpLsl, regTmpIndex, rlIndex.lowReg, scale);
1351 opRegReg(cUnit, kOpAdd, regPtr, regTmpIndex);
1352 freeTemp(cUnit, regTmpIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001353 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001354 opRegReg(cUnit, kOpAdd, regPtr, rlIndex.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001355 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001356 /* Combine address and index */
1357 if ((size == kLong) || (size == kDouble)) {
1358 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
1359 } else {
1360 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
1361 }
Jeff Hao97319a82009-08-12 16:57:15 -07001362
Bill Buzbee1465db52009-09-23 17:17:35 -07001363 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | regPtr;
Jeff Hao97319a82009-08-12 16:57:15 -07001364 selfVerificationMemOpWrapper(cUnit, regMap, funct);
1365
Jeff Hao97319a82009-08-12 16:57:15 -07001366#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001367}
1368
Bill Buzbee1465db52009-09-23 17:17:35 -07001369static bool handleShiftOpLong(CompilationUnit *cUnit, MIR *mir,
1370 RegLocation rlDest, RegLocation rlSrc1,
1371 RegLocation rlShift)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001372{
Ben Chenge9695e52009-06-16 16:11:47 -07001373 /*
1374 * Don't mess with the regsiters here as there is a particular calling
1375 * convention to the out-of-line handler.
1376 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001377 RegLocation rlResult;
1378
1379 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1380 loadValueDirect(cUnit, rlShift, r2);
Ben Chenge9695e52009-06-16 16:11:47 -07001381 switch( mir->dalvikInsn.opCode) {
1382 case OP_SHL_LONG:
1383 case OP_SHL_LONG_2ADDR:
1384 genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
1385 break;
1386 case OP_SHR_LONG:
1387 case OP_SHR_LONG_2ADDR:
1388 genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
1389 break;
1390 case OP_USHR_LONG:
1391 case OP_USHR_LONG_2ADDR:
1392 genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
1393 break;
1394 default:
1395 return true;
1396 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001397 rlResult = getReturnLocWide(cUnit);
1398 storeValueWide(cUnit, rlDest, rlResult);
Ben Chenge9695e52009-06-16 16:11:47 -07001399 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001400}
Bill Buzbee1465db52009-09-23 17:17:35 -07001401bool handleArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
1402 RegLocation rlDest, RegLocation rlSrc1,
1403 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001404{
Bill Buzbee1465db52009-09-23 17:17:35 -07001405 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001406 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001407
Ben Chengba4fc8b2009-06-01 13:00:29 -07001408 /* TODO: use a proper include file to define these */
1409 float __aeabi_fadd(float a, float b);
1410 float __aeabi_fsub(float a, float b);
1411 float __aeabi_fdiv(float a, float b);
1412 float __aeabi_fmul(float a, float b);
1413 float fmodf(float a, float b);
1414
1415 switch (mir->dalvikInsn.opCode) {
1416 case OP_ADD_FLOAT_2ADDR:
1417 case OP_ADD_FLOAT:
1418 funct = (void*) __aeabi_fadd;
1419 break;
1420 case OP_SUB_FLOAT_2ADDR:
1421 case OP_SUB_FLOAT:
1422 funct = (void*) __aeabi_fsub;
1423 break;
1424 case OP_DIV_FLOAT_2ADDR:
1425 case OP_DIV_FLOAT:
1426 funct = (void*) __aeabi_fdiv;
1427 break;
1428 case OP_MUL_FLOAT_2ADDR:
1429 case OP_MUL_FLOAT:
1430 funct = (void*) __aeabi_fmul;
1431 break;
1432 case OP_REM_FLOAT_2ADDR:
1433 case OP_REM_FLOAT:
1434 funct = (void*) fmodf;
1435 break;
1436 case OP_NEG_FLOAT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001437 genNegFloat(cUnit, rlDest, rlSrc1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001438 return false;
1439 }
1440 default:
1441 return true;
1442 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001443 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001444 loadValueDirectFixed(cUnit, rlSrc1, r0);
1445 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001446 loadConstant(cUnit, r2, (int)funct);
Bill Buzbee1465db52009-09-23 17:17:35 -07001447 opReg(cUnit, kOpBlx, r2);
1448 clobberCallRegs(cUnit);
1449 rlResult = getReturnLoc(cUnit);
1450 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001451 return false;
1452}
1453
Bill Buzbee1465db52009-09-23 17:17:35 -07001454bool handleArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
1455 RegLocation rlDest, RegLocation rlSrc1,
1456 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001457{
Bill Buzbee1465db52009-09-23 17:17:35 -07001458 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001459 void* funct;
Ben Chenge9695e52009-06-16 16:11:47 -07001460
Ben Chengba4fc8b2009-06-01 13:00:29 -07001461 /* TODO: use a proper include file to define these */
1462 double __aeabi_dadd(double a, double b);
1463 double __aeabi_dsub(double a, double b);
1464 double __aeabi_ddiv(double a, double b);
1465 double __aeabi_dmul(double a, double b);
1466 double fmod(double a, double b);
1467
1468 switch (mir->dalvikInsn.opCode) {
1469 case OP_ADD_DOUBLE_2ADDR:
1470 case OP_ADD_DOUBLE:
1471 funct = (void*) __aeabi_dadd;
1472 break;
1473 case OP_SUB_DOUBLE_2ADDR:
1474 case OP_SUB_DOUBLE:
1475 funct = (void*) __aeabi_dsub;
1476 break;
1477 case OP_DIV_DOUBLE_2ADDR:
1478 case OP_DIV_DOUBLE:
1479 funct = (void*) __aeabi_ddiv;
1480 break;
1481 case OP_MUL_DOUBLE_2ADDR:
1482 case OP_MUL_DOUBLE:
1483 funct = (void*) __aeabi_dmul;
1484 break;
1485 case OP_REM_DOUBLE_2ADDR:
1486 case OP_REM_DOUBLE:
1487 funct = (void*) fmod;
1488 break;
1489 case OP_NEG_DOUBLE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001490 genNegDouble(cUnit, rlDest, rlSrc1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001491 return false;
1492 }
1493 default:
1494 return true;
1495 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001496 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001497 loadConstant(cUnit, rlr, (int)funct);
1498 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1499 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1500 opReg(cUnit, kOpBlx, rlr);
1501 clobberCallRegs(cUnit);
1502 rlResult = getReturnLocWide(cUnit);
1503 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001504 return false;
1505}
1506
Bill Buzbee1465db52009-09-23 17:17:35 -07001507static bool handleArithOpLong(CompilationUnit *cUnit, MIR *mir,
1508 RegLocation rlDest, RegLocation rlSrc1,
1509 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001510{
Bill Buzbee1465db52009-09-23 17:17:35 -07001511 RegLocation rlResult;
1512 OpKind firstOp = kOpBkpt;
1513 OpKind secondOp = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001514 bool callOut = false;
1515 void *callTgt;
1516 int retReg = r0;
1517 /* TODO - find proper .h file to declare these */
1518 long long __aeabi_ldivmod(long long op1, long long op2);
1519
1520 switch (mir->dalvikInsn.opCode) {
1521 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07001522 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1523 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1524 opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
1525 opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
1526 storeValueWide(cUnit, rlDest, rlResult);
1527 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001528 break;
1529 case OP_ADD_LONG:
1530 case OP_ADD_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001531 firstOp = kOpAdd;
1532 secondOp = kOpAdc;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001533 break;
1534 case OP_SUB_LONG:
1535 case OP_SUB_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001536 firstOp = kOpSub;
1537 secondOp = kOpSbc;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001538 break;
1539 case OP_MUL_LONG:
1540 case OP_MUL_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001541 genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001542 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001543 case OP_DIV_LONG:
1544 case OP_DIV_LONG_2ADDR:
1545 callOut = true;
1546 retReg = r0;
1547 callTgt = (void*)__aeabi_ldivmod;
1548 break;
1549 /* NOTE - result is in r2/r3 instead of r0/r1 */
1550 case OP_REM_LONG:
1551 case OP_REM_LONG_2ADDR:
1552 callOut = true;
1553 callTgt = (void*)__aeabi_ldivmod;
1554 retReg = r2;
1555 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001556 case OP_AND_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001557 case OP_AND_LONG:
1558 firstOp = kOpAnd;
1559 secondOp = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001560 break;
1561 case OP_OR_LONG:
1562 case OP_OR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001563 firstOp = kOpOr;
1564 secondOp = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001565 break;
1566 case OP_XOR_LONG:
1567 case OP_XOR_LONG_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001568 firstOp = kOpXor;
1569 secondOp = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001570 break;
Ben Chenge9695e52009-06-16 16:11:47 -07001571 case OP_NEG_LONG: {
Bill Buzbee1465db52009-09-23 17:17:35 -07001572 rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
1573 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1574 loadConstantValue(cUnit, rlResult.highReg, 0);
1575 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
1576 rlResult.highReg, rlSrc2.lowReg);
1577 opRegReg(cUnit, kOpSbc, rlResult.highReg, rlSrc2.highReg);
1578 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001579 return false;
Ben Chenge9695e52009-06-16 16:11:47 -07001580 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001581 default:
1582 LOGE("Invalid long arith op");
1583 dvmAbort();
1584 }
1585 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001586 genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001587 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001588 // Adjust return regs in to handle case of rem returning r2/r3
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001589 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001590 loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
1591 loadConstant(cUnit, rlr, (int) callTgt);
1592 loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
1593 opReg(cUnit, kOpBlx, rlr);
1594 clobberCallRegs(cUnit);
1595 if (retReg == r0)
1596 rlResult = getReturnLocWide(cUnit);
1597 else
1598 rlResult = getReturnLocWideAlt(cUnit);
1599 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001600 }
1601 return false;
1602}
1603
Bill Buzbee1465db52009-09-23 17:17:35 -07001604static bool handleArithOpInt(CompilationUnit *cUnit, MIR *mir,
1605 RegLocation rlDest, RegLocation rlSrc1,
1606 RegLocation rlSrc2)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001607{
Bill Buzbee1465db52009-09-23 17:17:35 -07001608 OpKind op = kOpBkpt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001609 bool callOut = false;
1610 bool checkZero = false;
Bill Buzbee1465db52009-09-23 17:17:35 -07001611 bool unary = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001612 int retReg = r0;
1613 void *callTgt;
Bill Buzbee1465db52009-09-23 17:17:35 -07001614 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001615
1616 /* TODO - find proper .h file to declare these */
1617 int __aeabi_idivmod(int op1, int op2);
1618 int __aeabi_idiv(int op1, int op2);
1619
1620 switch (mir->dalvikInsn.opCode) {
1621 case OP_NEG_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001622 op = kOpNeg;
1623 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001624 break;
1625 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07001626 op = kOpMvn;
1627 unary = true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001628 break;
1629 case OP_ADD_INT:
1630 case OP_ADD_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001631 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001632 break;
1633 case OP_SUB_INT:
1634 case OP_SUB_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001635 op = kOpSub;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001636 break;
1637 case OP_MUL_INT:
1638 case OP_MUL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001639 op = kOpMul;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001640 break;
1641 case OP_DIV_INT:
1642 case OP_DIV_INT_2ADDR:
1643 callOut = true;
1644 checkZero = true;
1645 callTgt = __aeabi_idiv;
1646 retReg = r0;
1647 break;
1648 /* NOTE: returns in r1 */
1649 case OP_REM_INT:
1650 case OP_REM_INT_2ADDR:
1651 callOut = true;
1652 checkZero = true;
1653 callTgt = __aeabi_idivmod;
1654 retReg = r1;
1655 break;
1656 case OP_AND_INT:
1657 case OP_AND_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001658 op = kOpAnd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001659 break;
1660 case OP_OR_INT:
1661 case OP_OR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001662 op = kOpOr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001663 break;
1664 case OP_XOR_INT:
1665 case OP_XOR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001666 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001667 break;
1668 case OP_SHL_INT:
1669 case OP_SHL_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001670 op = kOpLsl;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001671 break;
1672 case OP_SHR_INT:
1673 case OP_SHR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001674 op = kOpAsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001675 break;
1676 case OP_USHR_INT:
1677 case OP_USHR_INT_2ADDR:
Bill Buzbee1465db52009-09-23 17:17:35 -07001678 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001679 break;
1680 default:
1681 LOGE("Invalid word arith op: 0x%x(%d)",
1682 mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
1683 dvmAbort();
1684 }
1685 if (!callOut) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001686 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
1687 if (unary) {
1688 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1689 opRegReg(cUnit, op, rlResult.lowReg,
1690 rlSrc1.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001691 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001692 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
1693 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
1694 opRegRegReg(cUnit, op, rlResult.lowReg,
1695 rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chenge9695e52009-06-16 16:11:47 -07001696 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001697 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001698 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001699 RegLocation rlResult;
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001700 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07001701 loadValueDirectFixed(cUnit, rlSrc2, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001702 loadConstant(cUnit, r2, (int) callTgt);
Bill Buzbee1465db52009-09-23 17:17:35 -07001703 loadValueDirectFixed(cUnit, rlSrc1, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001704 if (checkZero) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001705 genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001706 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001707 opReg(cUnit, kOpBlx, r2);
1708 clobberCallRegs(cUnit);
1709 if (retReg == r0)
1710 rlResult = getReturnLoc(cUnit);
1711 else
1712 rlResult = getReturnLocAlt(cUnit);
1713 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001714 }
1715 return false;
1716}
1717
Bill Buzbee1465db52009-09-23 17:17:35 -07001718static bool handleArithOp(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001719{
1720 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07001721 RegLocation rlDest;
1722 RegLocation rlSrc1;
1723 RegLocation rlSrc2;
1724 /* Deduce sizes of operands */
1725 if (mir->ssaRep->numUses == 2) {
1726 rlSrc1 = getSrcLoc(cUnit, mir, 0);
1727 rlSrc2 = getSrcLoc(cUnit, mir, 1);
1728 } else if (mir->ssaRep->numUses == 3) {
1729 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1730 rlSrc2 = getSrcLoc(cUnit, mir, 2);
1731 } else {
1732 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
1733 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
1734 assert(mir->ssaRep->numUses == 4);
1735 }
1736 if (mir->ssaRep->numDefs == 1) {
1737 rlDest = getDestLoc(cUnit, mir, 0);
1738 } else {
1739 assert(mir->ssaRep->numDefs == 2);
1740 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1741 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001742
1743 if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001744 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001745 }
1746 if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001747 return handleArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001748 }
1749 if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001750 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001751 }
1752 if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001753 return handleShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001754 }
1755 if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001756 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001757 }
1758 if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001759 return handleArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001760 }
1761 if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001762 return handleArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001763 }
1764 if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001765 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001766 }
1767 if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001768 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001769 }
1770 if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001771 return handleArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001772 }
1773 return true;
1774}
1775
Bill Buzbee1465db52009-09-23 17:17:35 -07001776/* Generate conditional branch instructions */
1777static ArmLIR *genConditionalBranch(CompilationUnit *cUnit,
1778 ArmConditionCode cond,
1779 ArmLIR *target)
1780{
1781 ArmLIR *branch = opCondBranch(cUnit, cond);
1782 branch->generic.target = (LIR *) target;
1783 return branch;
1784}
1785
1786/* Generate unconditional branch instructions */
1787static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
1788{
1789 ArmLIR *branch = opNone(cUnit, kOpUncondBr);
1790 branch->generic.target = (LIR *) target;
1791 return branch;
1792}
1793
1794/*
1795 * Generate an kArmPseudoBarrier marker to indicate the boundary of special
1796 * blocks.
1797 */
1798static void genBarrier(CompilationUnit *cUnit)
1799{
1800 ArmLIR *barrier = newLIR0(cUnit, kArmPseudoBarrier);
1801 /* Mark all resources as being clobbered */
1802 barrier->defMask = -1;
1803}
1804
1805/* Perform the actual operation for OP_RETURN_* */
1806static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
1807{
1808 genDispatchToHandler(cUnit, TEMPLATE_RETURN);
1809#if defined(INVOKE_STATS)
1810 gDvmJit.returnOp++;
1811#endif
1812 int dPC = (int) (cUnit->method->insns + mir->offset);
1813 /* Insert branch, but defer setting of target */
1814 ArmLIR *branch = genUnconditionalBranch(cUnit, NULL);
1815 /* Set up the place holder to reconstruct this Dalvik PC */
1816 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
1817 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
1818 pcrLabel->operands[0] = dPC;
1819 pcrLabel->operands[1] = mir->offset;
1820 /* Insert the place holder to the growable list */
1821 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
1822 /* Branch to the PC reconstruction code */
1823 branch->generic.target = (LIR *) pcrLabel;
1824}
1825
Bill Buzbeed45ba372009-06-15 17:00:57 -07001826static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
1827 int srcSize, int tgtSize)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001828{
Ben Chenge9695e52009-06-16 16:11:47 -07001829 /*
1830 * Don't optimize the register usage since it calls out to template
1831 * functions
1832 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001833 RegLocation rlSrc;
1834 RegLocation rlDest;
Bill Buzbeefd023aa2009-11-02 09:23:49 -08001835 flushAllRegs(cUnit); /* Send everything to home location */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001836 if (srcSize == 1) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001837 rlSrc = getSrcLoc(cUnit, mir, 0);
1838 loadValueDirectFixed(cUnit, rlSrc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001839 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001840 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
1841 loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001842 }
Bill Buzbee1465db52009-09-23 17:17:35 -07001843 loadConstant(cUnit, r2, (int)funct);
1844 opReg(cUnit, kOpBlx, r2);
1845 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001846 if (tgtSize == 1) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001847 RegLocation rlResult;
1848 rlDest = getDestLoc(cUnit, mir, 0);
1849 rlResult = getReturnLoc(cUnit);
1850 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001851 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -07001852 RegLocation rlResult;
1853 rlDest = getDestLocWide(cUnit, mir, 0, 1);
1854 rlResult = getReturnLocWide(cUnit);
1855 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001856 }
1857 return false;
1858}
1859
Ben Chengba4fc8b2009-06-01 13:00:29 -07001860static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
1861 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001862 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001863{
1864 unsigned int i;
1865 unsigned int regMask = 0;
Bill Buzbee1465db52009-09-23 17:17:35 -07001866 RegLocation rlArg;
1867 int numDone = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001868
Bill Buzbee1465db52009-09-23 17:17:35 -07001869 /*
1870 * Load arguments to r0..r4. Note that these registers may contain
1871 * live values, so we clobber them immediately after loading to prevent
1872 * them from being used as sources for subsequent loads.
1873 */
1874 lockAllTemps(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001875 for (i = 0; i < dInsn->vA; i++) {
1876 regMask |= 1 << i;
Bill Buzbee1465db52009-09-23 17:17:35 -07001877 rlArg = getSrcLoc(cUnit, mir, numDone++);
1878 loadValueDirectFixed(cUnit, rlArg, i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001879 }
1880 if (regMask) {
1881 /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
Bill Buzbee1465db52009-09-23 17:17:35 -07001882 opRegRegImm(cUnit, kOpSub, r7, rFP,
1883 sizeof(StackSaveArea) + (dInsn->vA << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001884 /* generate null check */
1885 if (pcrLabel) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001886 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1887 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001888 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001889 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001890 }
1891}
1892
1893static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
1894 DecodedInstruction *dInsn,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001895 ArmLIR **pcrLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001896{
1897 int srcOffset = dInsn->vC << 2;
1898 int numArgs = dInsn->vA;
1899 int regMask;
Bill Buzbee1465db52009-09-23 17:17:35 -07001900
1901 /*
1902 * Note: here, all promoted registers will have been flushed
1903 * back to the Dalvik base locations, so register usage restrictins
1904 * are lifted. All parms loaded from original Dalvik register
1905 * region - even though some might conceivably have valid copies
1906 * cached in a preserved register.
1907 */
1908 lockAllTemps(cUnit);
1909
Ben Chengba4fc8b2009-06-01 13:00:29 -07001910 /*
1911 * r4PC : &rFP[vC]
1912 * r7: &newFP[0]
1913 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001914 opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001915 /* load [r0 .. min(numArgs,4)] */
1916 regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001917 /*
1918 * Protect the loadMultiple instruction from being reordered with other
1919 * Dalvik stack accesses.
1920 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001921 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001922
Bill Buzbee1465db52009-09-23 17:17:35 -07001923 opRegRegImm(cUnit, kOpSub, r7, rFP,
1924 sizeof(StackSaveArea) + (numArgs << 2));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001925 /* generate null check */
1926 if (pcrLabel) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001927 *pcrLabel = genNullCheck(cUnit, getSrcSSAName(mir, 0), r0,
1928 mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001929 }
1930
1931 /*
1932 * Handle remaining 4n arguments:
1933 * store previously loaded 4 values and load the next 4 values
1934 */
1935 if (numArgs >= 8) {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001936 ArmLIR *loopLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001937 /*
1938 * r0 contains "this" and it will be used later, so push it to the stack
Bill Buzbee270c1d62009-08-13 16:58:07 -07001939 * first. Pushing r5 (rFP) is just for stack alignment purposes.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001940 */
Bill Buzbee1465db52009-09-23 17:17:35 -07001941 opImm(cUnit, kOpPush, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001942 /* No need to generate the loop structure if numArgs <= 11 */
1943 if (numArgs > 11) {
1944 loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
Bill Buzbee1465db52009-09-23 17:17:35 -07001945 loopLabel = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07001946 loopLabel->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001947 }
Bill Buzbee270c1d62009-08-13 16:58:07 -07001948 storeMultiple(cUnit, r7, regMask);
Ben Chengd7d426a2009-09-22 11:23:36 -07001949 /*
1950 * Protect the loadMultiple instruction from being reordered with other
1951 * Dalvik stack accesses.
1952 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001953 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001954 /* No need to generate the loop structure if numArgs <= 11 */
1955 if (numArgs > 11) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001956 opRegImm(cUnit, kOpSub, rFP, 4);
1957 genConditionalBranch(cUnit, kArmCondNe, loopLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001958 }
1959 }
1960
1961 /* Save the last batch of loaded values */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001962 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001963
1964 /* Generate the loop epilogue - don't use r0 */
1965 if ((numArgs > 4) && (numArgs % 4)) {
1966 regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
Ben Chengd7d426a2009-09-22 11:23:36 -07001967 /*
1968 * Protect the loadMultiple instruction from being reordered with other
1969 * Dalvik stack accesses.
1970 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07001971 loadMultiple(cUnit, r4PC, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001972 }
1973 if (numArgs >= 8)
Bill Buzbee1465db52009-09-23 17:17:35 -07001974 opImm(cUnit, kOpPop, (1 << r0 | 1 << rFP));
Ben Chengba4fc8b2009-06-01 13:00:29 -07001975
1976 /* Save the modulo 4 arguments */
1977 if ((numArgs > 4) && (numArgs % 4)) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07001978 storeMultiple(cUnit, r7, regMask);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001979 }
1980}
1981
Ben Cheng38329f52009-07-07 14:19:20 -07001982/*
1983 * Generate code to setup the call stack then jump to the chaining cell if it
1984 * is not a native method.
1985 */
1986static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001987 BasicBlock *bb, ArmLIR *labelList,
1988 ArmLIR *pcrLabel,
Ben Cheng38329f52009-07-07 14:19:20 -07001989 const Method *calleeMethod)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001990{
Bill Buzbee1465db52009-09-23 17:17:35 -07001991 /*
1992 * Note: all Dalvik register state should be flushed to
1993 * memory by the point, so register usage restrictions no
1994 * longer apply. All temp & preserved registers may be used.
1995 */
1996 lockAllTemps(cUnit);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07001997 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07001998
1999 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002000 lockTemp(cUnit, r1);
2001 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002002 /* r4PC = dalvikCallsite */
2003 loadConstant(cUnit, r4PC,
2004 (int) (cUnit->method->insns + mir->offset));
2005 addrRetChain->generic.target = (LIR *) retChainingCell;
2006 /*
Ben Cheng38329f52009-07-07 14:19:20 -07002007 * r0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002008 * r1 = &ChainingCell
2009 * r4PC = callsiteDPC
2010 */
2011 if (dvmIsNativeMethod(calleeMethod)) {
Ben Cheng38329f52009-07-07 14:19:20 -07002012 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NATIVE);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002013#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07002014 gDvmJit.invokeNative++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002015#endif
2016 } else {
2017 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
2018#if defined(INVOKE_STATS)
2019 gDvmJit.invokeChain++;
2020#endif
Ben Cheng38329f52009-07-07 14:19:20 -07002021 /* Branch to the chaining cell */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002022 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2023 }
2024 /* Handle exceptions using the interpreter */
2025 genTrap(cUnit, mir->offset, pcrLabel);
2026}
2027
Ben Cheng38329f52009-07-07 14:19:20 -07002028/*
2029 * Generate code to check the validity of a predicted chain and take actions
2030 * based on the result.
2031 *
2032 * 0x426a99aa : ldr r4, [pc, #72] --> r4 <- dalvikPC of this invoke
2033 * 0x426a99ac : add r1, pc, #32 --> r1 <- &retChainingCell
2034 * 0x426a99ae : add r2, pc, #40 --> r2 <- &predictedChainingCell
2035 * 0x426a99b0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
2036 * 0x426a99b2 : blx_2 see above --+
2037 * 0x426a99b4 : b 0x426a99d8 --> off to the predicted chain
2038 * 0x426a99b6 : b 0x426a99c8 --> punt to the interpreter
2039 * 0x426a99b8 : ldr r0, [r7, #44] --> r0 <- this->class->vtable[methodIdx]
2040 * 0x426a99ba : cmp r1, #0 --> compare r1 (rechain count) against 0
2041 * 0x426a99bc : bgt 0x426a99c2 --> >=0? don't rechain
2042 * 0x426a99be : ldr r7, [r6, #96] --+ dvmJitToPatchPredictedChain
2043 * 0x426a99c0 : blx r7 --+
2044 * 0x426a99c2 : add r1, pc, #12 --> r1 <- &retChainingCell
2045 * 0x426a99c4 : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
2046 * 0x426a99c6 : blx_2 see above --+
2047 */
2048static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
2049 int methodIndex,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002050 ArmLIR *retChainingCell,
2051 ArmLIR *predChainingCell,
2052 ArmLIR *pcrLabel)
Ben Cheng38329f52009-07-07 14:19:20 -07002053{
Bill Buzbee1465db52009-09-23 17:17:35 -07002054 /*
2055 * Note: all Dalvik register state should be flushed to
2056 * memory by the point, so register usage restrictions no
2057 * longer apply. Lock temps to prevent them from being
2058 * allocated by utility routines.
2059 */
2060 lockAllTemps(cUnit);
2061
Ben Cheng38329f52009-07-07 14:19:20 -07002062 /* "this" is already left in r0 by genProcessArgs* */
2063
2064 /* r4PC = dalvikCallsite */
2065 loadConstant(cUnit, r4PC,
2066 (int) (cUnit->method->insns + mir->offset));
2067
2068 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002069 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002070 addrRetChain->generic.target = (LIR *) retChainingCell;
2071
2072 /* r2 = &predictedChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002073 ArmLIR *predictedChainingCell = opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002074 predictedChainingCell->generic.target = (LIR *) predChainingCell;
2075
2076 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
2077
2078 /* return through lr - jump to the chaining cell */
2079 genUnconditionalBranch(cUnit, predChainingCell);
2080
2081 /*
2082 * null-check on "this" may have been eliminated, but we still need a PC-
2083 * reconstruction label for stack overflow bailout.
2084 */
2085 if (pcrLabel == NULL) {
2086 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002087 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07002088 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07002089 pcrLabel->operands[0] = dPC;
2090 pcrLabel->operands[1] = mir->offset;
2091 /* Insert the place holder to the growable list */
2092 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
2093 }
2094
2095 /* return through lr+2 - punt to the interpreter */
2096 genUnconditionalBranch(cUnit, pcrLabel);
2097
2098 /*
2099 * return through lr+4 - fully resolve the callee method.
2100 * r1 <- count
2101 * r2 <- &predictedChainCell
2102 * r3 <- this->class
2103 * r4 <- dPC
2104 * r7 <- this->class->vtable
2105 */
2106
2107 /* r0 <- calleeMethod */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002108 loadWordDisp(cUnit, r7, methodIndex * 4, r0);
Ben Cheng38329f52009-07-07 14:19:20 -07002109
2110 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07002111 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002112
Bill Buzbee1465db52009-09-23 17:17:35 -07002113 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07002114
Bill Buzbee270c1d62009-08-13 16:58:07 -07002115 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2116 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002117
2118 /*
2119 * r0 = calleeMethod
2120 * r2 = &predictedChainingCell
2121 * r3 = class
2122 *
2123 * &returnChainingCell has been loaded into r1 but is not needed
2124 * when patching the chaining cell and will be clobbered upon
2125 * returning so it will be reconstructed again.
2126 */
Bill Buzbee1465db52009-09-23 17:17:35 -07002127 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002128
2129 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002130 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002131 addrRetChain->generic.target = (LIR *) retChainingCell;
2132
2133 bypassRechaining->generic.target = (LIR *) addrRetChain;
2134 /*
2135 * r0 = calleeMethod,
2136 * r1 = &ChainingCell,
2137 * r4PC = callsiteDPC,
2138 */
2139 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
2140#if defined(INVOKE_STATS)
2141 gDvmJit.invokePredictedChain++;
2142#endif
2143 /* Handle exceptions using the interpreter */
2144 genTrap(cUnit, mir->offset, pcrLabel);
2145}
2146
2147/*
2148 * Up calling this function, "this" is stored in r0. The actual class will be
2149 * chased down off r0 and the predicted one will be retrieved through
2150 * predictedChainingCell then a comparison is performed to see whether the
2151 * previously established chaining is still valid.
2152 *
2153 * The return LIR is a branch based on the comparison result. The actual branch
2154 * target will be setup in the caller.
2155 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002156static ArmLIR *genCheckPredictedChain(CompilationUnit *cUnit,
2157 ArmLIR *predChainingCell,
2158 ArmLIR *retChainingCell,
Ben Cheng38329f52009-07-07 14:19:20 -07002159 MIR *mir)
2160{
Bill Buzbee1465db52009-09-23 17:17:35 -07002161 /*
2162 * Note: all Dalvik register state should be flushed to
2163 * memory by the point, so register usage restrictions no
2164 * longer apply. All temp & preserved registers may be used.
2165 */
2166 lockAllTemps(cUnit);
2167
Ben Cheng38329f52009-07-07 14:19:20 -07002168 /* r3 now contains this->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002169 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002170
2171 /*
2172 * r2 now contains predicted class. The starting offset of the
2173 * cached value is 4 bytes into the chaining cell.
2174 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002175 ArmLIR *getPredictedClass =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002176 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, clazz), r2);
Ben Cheng38329f52009-07-07 14:19:20 -07002177 getPredictedClass->generic.target = (LIR *) predChainingCell;
2178
2179 /*
2180 * r0 now contains predicted method. The starting offset of the
2181 * cached value is 8 bytes into the chaining cell.
2182 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002183 ArmLIR *getPredictedMethod =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002184 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, method), r0);
Ben Cheng38329f52009-07-07 14:19:20 -07002185 getPredictedMethod->generic.target = (LIR *) predChainingCell;
2186
2187 /* Load the stats counter to see if it is time to unchain and refresh */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002188 ArmLIR *getRechainingRequestCount =
Bill Buzbee270c1d62009-08-13 16:58:07 -07002189 loadWordDisp(cUnit, rpc, offsetof(PredictedChainingCell, counter), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07002190 getRechainingRequestCount->generic.target =
2191 (LIR *) predChainingCell;
2192
2193 /* r4PC = dalvikCallsite */
2194 loadConstant(cUnit, r4PC,
2195 (int) (cUnit->method->insns + mir->offset));
2196
2197 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07002198 ArmLIR *addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07002199 addrRetChain->generic.target = (LIR *) retChainingCell;
2200
2201 /* Check if r2 (predicted class) == r3 (actual class) */
Bill Buzbee1465db52009-09-23 17:17:35 -07002202 opRegReg(cUnit, kOpCmp, r2, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07002203
Bill Buzbee1465db52009-09-23 17:17:35 -07002204 return opCondBranch(cUnit, kArmCondEq);
Ben Cheng38329f52009-07-07 14:19:20 -07002205}
2206
Ben Chengba4fc8b2009-06-01 13:00:29 -07002207/* Geneate a branch to go back to the interpreter */
2208static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
2209{
2210 /* r0 = dalvik pc */
Bill Buzbee1465db52009-09-23 17:17:35 -07002211 flushAllRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002212 loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
Bill Buzbee270c1d62009-08-13 16:58:07 -07002213 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r3);
2214 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
2215 jitToInterpEntries.dvmJitToInterpPunt), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07002216 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002217}
2218
2219/*
2220 * Attempt to single step one instruction using the interpreter and return
2221 * to the compiled code for the next Dalvik instruction
2222 */
2223static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
2224{
2225 int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
2226 int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
2227 kInstrCanThrow;
Bill Buzbee1465db52009-09-23 17:17:35 -07002228
2229 //Ugly, but necessary. Flush all Dalvik regs so Interp can find them
2230 flushAllRegs(cUnit);
2231
Ben Chengba4fc8b2009-06-01 13:00:29 -07002232 if ((mir->next == NULL) || (flags & flagsToCheck)) {
2233 genPuntToInterp(cUnit, mir->offset);
2234 return;
2235 }
2236 int entryAddr = offsetof(InterpState,
2237 jitToInterpEntries.dvmJitToInterpSingleStep);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002238 loadWordDisp(cUnit, rGLUE, entryAddr, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002239 /* r0 = dalvik pc */
2240 loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
2241 /* r1 = dalvik pc of following instruction */
2242 loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
Bill Buzbee1465db52009-09-23 17:17:35 -07002243 opReg(cUnit, kOpBlx, r2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002244}
2245
Bill Buzbee1465db52009-09-23 17:17:35 -07002246static void handleMonitorPortable(CompilationUnit *cUnit, MIR *mir)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002247{
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08002248 bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002249 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002250 genExportPC(cUnit, mir);
2251 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2252 loadValueDirectFixed(cUnit, rlSrc, r1);
2253 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08002254 if (isEnter) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002255 loadConstant(cUnit, r2, (int)dvmLockObject);
2256 } else {
2257 loadConstant(cUnit, r2, (int)dvmUnlockObject);
2258 }
2259 genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
2260 /* Do the call */
2261 opReg(cUnit, kOpBlx, r2);
Bill Buzbeeefbd3c52009-11-04 22:18:40 -08002262#if defined(WITH_DEADLOCK_PREDICTION)
2263 if (isEnter) {
2264 loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0);
2265 loadWordDisp(cUnit, r0, offsetof(Thread, exception), r1);
2266 opRegImm(cUnit, kOpCmp, r1, 0);
2267 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondEq);
2268 loadConstant(cUnit, r0,
2269 (int) (cUnit->method->insns + mir->offset));
2270 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2271 /* noreturn */
2272 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
2273 target->defMask = ENCODE_ALL;
2274 branchOver->generic.target = (LIR *) target;
2275 }
2276#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002277 clobberCallRegs(cUnit);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002278}
2279
2280/* Load a word at base + displacement. Displacement must be word multiple */
2281static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
2282 int rDest)
2283{
Bill Buzbee1465db52009-09-23 17:17:35 -07002284 return loadBaseDisp(cUnit, NULL, rBase, displacement, rDest, kWord, false,
2285 INVALID_SREG);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002286}
2287
2288static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
Bill Buzbee1465db52009-09-23 17:17:35 -07002289 int displacement, int rSrc)
Bill Buzbee270c1d62009-08-13 16:58:07 -07002290{
Bill Buzbee1465db52009-09-23 17:17:35 -07002291 return storeBaseDisp(cUnit, rBase, displacement, rSrc, kWord);
Bill Buzbee270c1d62009-08-13 16:58:07 -07002292}
2293
2294static ArmLIR *genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
2295{
2296 ArmLIR *res = dvmCompilerRegCopy(cUnit, rDest, rSrc);
2297 dvmCompilerAppendLIR(cUnit, (LIR*)res);
2298 return res;
2299}
2300
Ben Chengba4fc8b2009-06-01 13:00:29 -07002301/*
2302 * The following are the first-level codegen routines that analyze the format
2303 * of each bytecode then either dispatch special purpose codegen routines
2304 * or produce corresponding Thumb instructions directly.
2305 */
2306
2307static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002308 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002309{
2310 /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
2311 genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
2312 return false;
2313}
2314
2315static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
2316{
2317 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
2318 if (((dalvikOpCode >= OP_UNUSED_3E) && (dalvikOpCode <= OP_UNUSED_43)) ||
2319 ((dalvikOpCode >= OP_UNUSED_E3) && (dalvikOpCode <= OP_UNUSED_EC))) {
2320 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2321 return true;
2322 }
2323 switch (dalvikOpCode) {
2324 case OP_RETURN_VOID:
2325 genReturnCommon(cUnit,mir);
2326 break;
2327 case OP_UNUSED_73:
2328 case OP_UNUSED_79:
2329 case OP_UNUSED_7A:
2330 LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
2331 return true;
2332 case OP_NOP:
2333 break;
2334 default:
2335 return true;
2336 }
2337 return false;
2338}
2339
2340static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
2341{
Bill Buzbee1465db52009-09-23 17:17:35 -07002342 RegLocation rlDest;
2343 RegLocation rlResult;
2344 if (mir->ssaRep->numDefs == 2) {
2345 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2346 } else {
2347 rlDest = getDestLoc(cUnit, mir, 0);
2348 }
Ben Chenge9695e52009-06-16 16:11:47 -07002349
Ben Chengba4fc8b2009-06-01 13:00:29 -07002350 switch (mir->dalvikInsn.opCode) {
2351 case OP_CONST:
Ben Chenge9695e52009-06-16 16:11:47 -07002352 case OP_CONST_4: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002353 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2354 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2355 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002356 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002357 }
2358 case OP_CONST_WIDE_32: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002359 //TUNING: single routine to load constant pair for support doubles
2360 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2361 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
2362 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2363 rlResult.lowReg, 31);
2364 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002365 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002366 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002367 default:
2368 return true;
2369 }
2370 return false;
2371}
2372
2373static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
2374{
Bill Buzbee1465db52009-09-23 17:17:35 -07002375 RegLocation rlDest;
2376 RegLocation rlResult;
2377 if (mir->ssaRep->numDefs == 2) {
2378 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2379 } else {
2380 rlDest = getDestLoc(cUnit, mir, 0);
2381 }
2382 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
Ben Chenge9695e52009-06-16 16:11:47 -07002383
Ben Chengba4fc8b2009-06-01 13:00:29 -07002384 switch (mir->dalvikInsn.opCode) {
Ben Chenge9695e52009-06-16 16:11:47 -07002385 case OP_CONST_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002386 loadConstantValue(cUnit, rlResult.lowReg, mir->dalvikInsn.vB << 16);
2387 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002388 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002389 }
2390 case OP_CONST_WIDE_HIGH16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002391 loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
2392 0, mir->dalvikInsn.vB << 16);
2393 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002394 break;
Ben Chenge9695e52009-06-16 16:11:47 -07002395 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002396 default:
2397 return true;
2398 }
2399 return false;
2400}
2401
2402static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
2403{
2404 /* For OP_THROW_VERIFICATION_ERROR */
2405 genInterpSingleStep(cUnit, mir);
2406 return false;
2407}
2408
2409static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
2410{
Bill Buzbee1465db52009-09-23 17:17:35 -07002411 RegLocation rlResult;
2412 RegLocation rlDest;
2413 RegLocation rlSrc;
Ben Chenge9695e52009-06-16 16:11:47 -07002414
Ben Chengba4fc8b2009-06-01 13:00:29 -07002415 switch (mir->dalvikInsn.opCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07002416 case OP_CONST_STRING_JUMBO:
2417 case OP_CONST_STRING: {
2418 void *strPtr = (void*)
2419 (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
2420 assert(strPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002421 rlDest = getDestLoc(cUnit, mir, 0);
2422 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2423 loadConstantValue(cUnit, rlResult.lowReg, (int) strPtr );
2424 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002425 break;
2426 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002427 case OP_CONST_CLASS: {
2428 void *classPtr = (void*)
2429 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2430 assert(classPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002431 rlDest = getDestLoc(cUnit, mir, 0);
2432 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2433 loadConstantValue(cUnit, rlResult.lowReg, (int) classPtr );
2434 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002435 break;
2436 }
2437 case OP_SGET_OBJECT:
2438 case OP_SGET_BOOLEAN:
2439 case OP_SGET_CHAR:
2440 case OP_SGET_BYTE:
2441 case OP_SGET_SHORT:
2442 case OP_SGET: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002443 int valOffset = offsetof(StaticField, value);
Bill Buzbee1465db52009-09-23 17:17:35 -07002444 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002445 void *fieldPtr = (void*)
2446 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
2447 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002448 rlDest = getDestLoc(cUnit, mir, 0);
2449 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2450 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002451#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002452 loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002453#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002454 int regMap = rlResult.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002455 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationLoad);
2456
Jeff Hao97319a82009-08-12 16:57:15 -07002457#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002458 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002459 break;
2460 }
2461 case OP_SGET_WIDE: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002462 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002463 void *fieldPtr = (void*)
2464 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Bill Buzbee1465db52009-09-23 17:17:35 -07002465 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002466 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002467 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2468 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2469 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002470#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002471 loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002472#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002473 int regMap = rlResult.highReg << 16 |
2474 rlResult.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002475 selfVerificationMemOpWrapper(cUnit, regMap,
2476 &selfVerificationLoadDoubleword);
2477
Jeff Hao97319a82009-08-12 16:57:15 -07002478#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07002479 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002480 break;
2481 }
2482 case OP_SPUT_OBJECT:
2483 case OP_SPUT_BOOLEAN:
2484 case OP_SPUT_CHAR:
2485 case OP_SPUT_BYTE:
2486 case OP_SPUT_SHORT:
2487 case OP_SPUT: {
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002488 int valOffset = offsetof(StaticField, value);
Bill Buzbee1465db52009-09-23 17:17:35 -07002489 int tReg = allocTemp(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002490 void *fieldPtr = (void*)
2491 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002492
Ben Chengba4fc8b2009-06-01 13:00:29 -07002493 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002494 rlSrc = getSrcLoc(cUnit, mir, 0);
2495 rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
2496 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002497#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002498 storeWordDisp(cUnit, tReg, 0 ,rlSrc.lowReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002499#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002500 int regMap = rlSrc.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002501 selfVerificationMemOpWrapper(cUnit, regMap, &selfVerificationStore);
2502#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002503 break;
2504 }
2505 case OP_SPUT_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002506 int tReg = allocTemp(cUnit);
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002507 int valOffset = offsetof(StaticField, value);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002508 void *fieldPtr = (void*)
2509 (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
Ben Chenge9695e52009-06-16 16:11:47 -07002510
Ben Chengba4fc8b2009-06-01 13:00:29 -07002511 assert(fieldPtr != NULL);
Bill Buzbee1465db52009-09-23 17:17:35 -07002512 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2513 rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
2514 loadConstant(cUnit, tReg, (int) fieldPtr + valOffset);
Jeff Hao97319a82009-08-12 16:57:15 -07002515#if !defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07002516 storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
Jeff Hao97319a82009-08-12 16:57:15 -07002517#else
Bill Buzbee1465db52009-09-23 17:17:35 -07002518 int regMap = rlSrc.highReg << 16 | rlSrc.lowReg << 8 | tReg;
Jeff Hao97319a82009-08-12 16:57:15 -07002519 selfVerificationMemOpWrapper(cUnit, regMap,
2520 &selfVerificationStoreDoubleword);
2521#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002522 break;
2523 }
2524 case OP_NEW_INSTANCE: {
Ben Chenge9695e52009-06-16 16:11:47 -07002525 /*
2526 * Obey the calling convention and don't mess with the register
2527 * usage.
2528 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002529 ClassObject *classPtr = (void*)
2530 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
2531 assert(classPtr != NULL);
2532 assert(classPtr->status & CLASS_INITIALIZED);
Ben Cheng79d173c2009-09-29 16:12:51 -07002533 /*
2534 * If it is going to throw, it should not make to the trace to begin
Bill Buzbee1465db52009-09-23 17:17:35 -07002535 * with. However, Alloc might throw, so we need to genExportPC()
Ben Cheng79d173c2009-09-29 16:12:51 -07002536 */
2537 assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002538 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002539 genExportPC(cUnit, mir);
2540 loadConstant(cUnit, r2, (int)dvmAllocObject);
Ben Chenge9695e52009-06-16 16:11:47 -07002541 loadConstant(cUnit, r0, (int) classPtr);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002542 loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07002543 opReg(cUnit, kOpBlx, r2);
2544 clobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07002545 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07002546 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
2547 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07002548 /*
2549 * OOM exception needs to be thrown here and cannot re-execute
2550 */
2551 loadConstant(cUnit, r0,
2552 (int) (cUnit->method->insns + mir->offset));
2553 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
2554 /* noreturn */
2555
Bill Buzbee1465db52009-09-23 17:17:35 -07002556 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07002557 target->defMask = ENCODE_ALL;
2558 branchOver->generic.target = (LIR *) target;
Bill Buzbee1465db52009-09-23 17:17:35 -07002559 rlDest = getDestLoc(cUnit, mir, 0);
2560 rlResult = getReturnLoc(cUnit);
2561 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002562 break;
2563 }
2564 case OP_CHECK_CAST: {
Ben Chenge9695e52009-06-16 16:11:47 -07002565 /*
2566 * Obey the calling convention and don't mess with the register
2567 * usage.
2568 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002569 ClassObject *classPtr =
2570 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
Bill Buzbee4df41a52009-11-12 17:07:16 -08002571 /*
2572 * Note: It is possible that classPtr is NULL at this point,
2573 * even though this instruction has been successfully interpreted.
2574 * If the previous interpretation had a null source, the
2575 * interpreter would not have bothered to resolve the clazz.
2576 * Bail out to the interpreter in this case, and log it
2577 * so that we can tell if it happens frequently.
2578 */
2579 if (classPtr == NULL) {
2580 LOGD("null clazz in OP_CHECK_CAST, single-stepping");
2581 genInterpSingleStep(cUnit, mir);
2582 return false;
2583 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002584 flushAllRegs(cUnit); /* Send everything to home location */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002585 loadConstant(cUnit, r1, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07002586 rlSrc = getSrcLoc(cUnit, mir, 0);
2587 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2588 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0); /* Null? */
2589 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
2590 /*
2591 * rlSrc.lowReg now contains object->clazz. Note that
2592 * it could have been allocated r0, but we're okay so long
2593 * as we don't do anything desctructive until r0 is loaded
2594 * with clazz.
2595 */
Ben Chengba4fc8b2009-06-01 13:00:29 -07002596 /* r0 now contains object->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07002597 loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r0);
2598 loadConstant(cUnit, r2, (int)dvmInstanceofNonTrivial);
2599 opRegReg(cUnit, kOpCmp, r0, r1);
2600 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
2601 opReg(cUnit, kOpBlx, r2);
2602 clobberCallRegs(cUnit);
2603 /*
2604 * If null, check cast failed - punt to the interpreter. Because
2605 * interpreter will be the one throwing, we don't need to
2606 * genExportPC() here.
2607 */
Bill Buzbee270c1d62009-08-13 16:58:07 -07002608 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002609 /* check cast passed - branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07002610 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07002611 target->defMask = ENCODE_ALL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002612 branch1->generic.target = (LIR *)target;
2613 branch2->generic.target = (LIR *)target;
2614 break;
2615 }
2616 default:
2617 return true;
2618 }
2619 return false;
2620}
2621
2622static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
2623{
2624 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002625 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002626 switch (dalvikOpCode) {
2627 case OP_MOVE_EXCEPTION: {
2628 int offset = offsetof(InterpState, self);
2629 int exOffset = offsetof(Thread, exception);
Bill Buzbee1465db52009-09-23 17:17:35 -07002630 int selfReg = allocTemp(cUnit);
2631 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2632 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2633 loadWordDisp(cUnit, rGLUE, offset, selfReg);
2634 loadWordDisp(cUnit, selfReg, exOffset, rlResult.lowReg);
2635 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002636 break;
2637 }
2638 case OP_MOVE_RESULT:
2639 case OP_MOVE_RESULT_OBJECT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002640 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2641 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
2642 rlSrc.fp = rlDest.fp;
2643 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002644 break;
2645 }
2646 case OP_MOVE_RESULT_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002647 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
2648 RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
2649 rlSrc.fp = rlDest.fp;
2650 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002651 break;
2652 }
2653 case OP_RETURN_WIDE: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002654 RegLocation rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2655 RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
2656 rlDest.fp = rlSrc.fp;
2657 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002658 genReturnCommon(cUnit,mir);
2659 break;
2660 }
2661 case OP_RETURN:
2662 case OP_RETURN_OBJECT: {
Bill Buzbee1465db52009-09-23 17:17:35 -07002663 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2664 RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
2665 rlDest.fp = rlSrc.fp;
2666 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002667 genReturnCommon(cUnit,mir);
2668 break;
2669 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002670 case OP_MONITOR_EXIT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002671 case OP_MONITOR_ENTER:
Bill Buzbee1465db52009-09-23 17:17:35 -07002672#if defined(WITH_DEADLOCK_PREDICTION) || defined(WITH_MONITOR_TRACKING)
2673 handleMonitorPortable(cUnit, mir);
2674#else
2675 handleMonitor(cUnit, mir);
2676#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07002677 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002678 case OP_THROW: {
2679 genInterpSingleStep(cUnit, mir);
2680 break;
2681 }
2682 default:
2683 return true;
2684 }
2685 return false;
2686}
2687
Bill Buzbee1465db52009-09-23 17:17:35 -07002688static bool handleConversionPortable(CompilationUnit *cUnit, MIR *mir)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002689{
2690 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002691
Ben Chengba4fc8b2009-06-01 13:00:29 -07002692 float __aeabi_i2f( int op1 );
2693 int __aeabi_f2iz( float op1 );
2694 float __aeabi_d2f( double op1 );
2695 double __aeabi_f2d( float op1 );
2696 double __aeabi_i2d( int op1 );
2697 int __aeabi_d2iz( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002698 float __aeabi_l2f( long op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002699 double __aeabi_l2d( long op1 );
Bill Buzbee270c1d62009-08-13 16:58:07 -07002700 s8 dvmJitf2l( float op1 );
2701 s8 dvmJitd2l( double op1 );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002702
Bill Buzbeed45ba372009-06-15 17:00:57 -07002703 switch (opCode) {
2704 case OP_INT_TO_FLOAT:
2705 return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
2706 case OP_FLOAT_TO_INT:
2707 return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
2708 case OP_DOUBLE_TO_FLOAT:
2709 return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
2710 case OP_FLOAT_TO_DOUBLE:
2711 return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
2712 case OP_INT_TO_DOUBLE:
2713 return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
2714 case OP_DOUBLE_TO_INT:
2715 return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
2716 case OP_FLOAT_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002717 return genConversionCall(cUnit, mir, (void*)dvmJitf2l, 1, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002718 case OP_LONG_TO_FLOAT:
2719 return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
2720 case OP_DOUBLE_TO_LONG:
Bill Buzbee50a6bf22009-07-08 13:08:04 -07002721 return genConversionCall(cUnit, mir, (void*)dvmJitd2l, 2, 2);
Bill Buzbeed45ba372009-06-15 17:00:57 -07002722 case OP_LONG_TO_DOUBLE:
2723 return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
2724 default:
2725 return true;
2726 }
2727 return false;
2728}
2729
2730static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
2731{
2732 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002733 RegLocation rlDest;
2734 RegLocation rlSrc;
2735 RegLocation rlResult;
Bill Buzbeed45ba372009-06-15 17:00:57 -07002736
Ben Chengba4fc8b2009-06-01 13:00:29 -07002737 if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002738 return handleArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07002739 }
2740
Bill Buzbee1465db52009-09-23 17:17:35 -07002741 if (mir->ssaRep->numUses == 2)
2742 rlSrc = getSrcLocWide(cUnit, mir, 0, 1);
2743 else
2744 rlSrc = getSrcLoc(cUnit, mir, 0);
2745 if (mir->ssaRep->numDefs == 2)
2746 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2747 else
2748 rlDest = getDestLoc(cUnit, mir, 0);
Ben Chenge9695e52009-06-16 16:11:47 -07002749
Ben Chengba4fc8b2009-06-01 13:00:29 -07002750 switch (opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002751 case OP_DOUBLE_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002752 case OP_INT_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002753 case OP_FLOAT_TO_INT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002754 case OP_DOUBLE_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002755 case OP_FLOAT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002756 case OP_INT_TO_DOUBLE:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002757 case OP_FLOAT_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002758 case OP_LONG_TO_FLOAT:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002759 case OP_DOUBLE_TO_LONG:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002760 case OP_LONG_TO_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002761 return handleConversion(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002762 case OP_NEG_INT:
2763 case OP_NOT_INT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002764 return handleArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002765 case OP_NEG_LONG:
2766 case OP_NOT_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07002767 return handleArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002768 case OP_NEG_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002769 return handleArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002770 case OP_NEG_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002771 return handleArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
2772 case OP_MOVE_WIDE:
2773 storeValueWide(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002774 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07002775 case OP_INT_TO_LONG:
2776 rlSrc = updateLoc(cUnit, rlSrc);
2777 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2778 if (rlSrc.location == kLocPhysReg) {
2779 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2780 } else {
2781 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
2782 }
2783 opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
2784 rlResult.lowReg, 31);
2785 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002786 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07002787 case OP_LONG_TO_INT:
2788 rlSrc = updateLocWide(cUnit, rlSrc);
2789 rlSrc = wideToNarrowLoc(cUnit, rlSrc);
2790 // Intentional fallthrough
Ben Chengba4fc8b2009-06-01 13:00:29 -07002791 case OP_MOVE:
2792 case OP_MOVE_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002793 storeValue(cUnit, rlDest, rlSrc);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002794 break;
2795 case OP_INT_TO_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07002796 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2797 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2798 opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
2799 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002800 break;
2801 case OP_INT_TO_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07002802 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2803 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2804 opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
2805 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002806 break;
2807 case OP_INT_TO_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07002808 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2809 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2810 opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
2811 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002812 break;
2813 case OP_ARRAY_LENGTH: {
2814 int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07002815 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2816 genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
2817 mir->offset, NULL);
2818 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2819 loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
2820 rlResult.lowReg);
2821 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002822 break;
2823 }
2824 default:
2825 return true;
2826 }
2827 return false;
2828}
2829
2830static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
2831{
2832 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002833 RegLocation rlDest;
2834 RegLocation rlResult;
2835 int BBBB = mir->dalvikInsn.vB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002836 if (dalvikOpCode == OP_CONST_WIDE_16) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002837 rlDest = getDestLocWide(cUnit, mir, 0, 1);
2838 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2839 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
2840 opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
2841 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002842 } else if (dalvikOpCode == OP_CONST_16) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002843 rlDest = getDestLoc(cUnit, mir, 0);
2844 rlResult = evalLoc(cUnit, rlDest, kAnyReg, true);
2845 loadConstantValue(cUnit, rlResult.lowReg, BBBB);
2846 storeValue(cUnit, rlDest, rlResult);
2847 } else
Ben Chengba4fc8b2009-06-01 13:00:29 -07002848 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002849 return false;
2850}
2851
2852/* Compare agaist zero */
2853static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002854 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07002855{
2856 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07002857 ArmConditionCode cond;
Bill Buzbee1465db52009-09-23 17:17:35 -07002858 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2859 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2860 opRegImm(cUnit, kOpCmp, rlSrc.lowReg, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002861
Bill Buzbee270c1d62009-08-13 16:58:07 -07002862//TUNING: break this out to allow use of Thumb2 CB[N]Z
Ben Chengba4fc8b2009-06-01 13:00:29 -07002863 switch (dalvikOpCode) {
2864 case OP_IF_EQZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002865 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002866 break;
2867 case OP_IF_NEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002868 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002869 break;
2870 case OP_IF_LTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002871 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002872 break;
2873 case OP_IF_GEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002874 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002875 break;
2876 case OP_IF_GTZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002877 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002878 break;
2879 case OP_IF_LEZ:
Bill Buzbee1465db52009-09-23 17:17:35 -07002880 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002881 break;
2882 default:
2883 cond = 0;
2884 LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
2885 dvmAbort();
2886 }
2887 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
2888 /* This mostly likely will be optimized away in a later phase */
2889 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
2890 return false;
2891}
2892
2893static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
2894{
2895 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07002896 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
2897 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
2898 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002899 int lit = mir->dalvikInsn.vC;
Ben Cheng4f489172009-09-27 17:08:35 -07002900 OpKind op = 0; /* Make gcc happy */
Bill Buzbee1465db52009-09-23 17:17:35 -07002901 int shiftOp = false;
2902 bool isDiv = false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002903
Ben Chengba4fc8b2009-06-01 13:00:29 -07002904 int __aeabi_idivmod(int op1, int op2);
2905 int __aeabi_idiv(int op1, int op2);
2906
2907 switch (dalvikOpCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07002908 case OP_RSUB_INT_LIT8:
2909 case OP_RSUB_INT: {
2910 int tReg;
2911 //TUNING: add support for use of Arm rsub op
2912 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2913 tReg = allocTemp(cUnit);
2914 loadConstant(cUnit, tReg, lit);
2915 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2916 opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
2917 tReg, rlSrc.lowReg);
2918 storeValue(cUnit, rlDest, rlResult);
2919 return false;
2920 break;
2921 }
2922
Ben Chengba4fc8b2009-06-01 13:00:29 -07002923 case OP_ADD_INT_LIT8:
2924 case OP_ADD_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002925 op = kOpAdd;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002926 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002927 case OP_MUL_INT_LIT8:
2928 case OP_MUL_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002929 op = kOpMul;
2930 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002931 case OP_AND_INT_LIT8:
2932 case OP_AND_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002933 op = kOpAnd;
2934 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002935 case OP_OR_INT_LIT8:
2936 case OP_OR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002937 op = kOpOr;
2938 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002939 case OP_XOR_INT_LIT8:
2940 case OP_XOR_INT_LIT16:
Bill Buzbee1465db52009-09-23 17:17:35 -07002941 op = kOpXor;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002942 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002943 case OP_SHL_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002944 shiftOp = true;
2945 op = kOpLsl;
2946 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002947 case OP_SHR_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002948 shiftOp = true;
2949 op = kOpAsr;
2950 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002951 case OP_USHR_INT_LIT8:
Bill Buzbee1465db52009-09-23 17:17:35 -07002952 shiftOp = true;
2953 op = kOpLsr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002954 break;
2955
2956 case OP_DIV_INT_LIT8:
2957 case OP_DIV_INT_LIT16:
Ben Chengba4fc8b2009-06-01 13:00:29 -07002958 case OP_REM_INT_LIT8:
2959 case OP_REM_INT_LIT16:
2960 if (lit == 0) {
2961 /* Let the interpreter deal with div by 0 */
2962 genInterpSingleStep(cUnit, mir);
2963 return false;
2964 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08002965 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07002966 loadValueDirectFixed(cUnit, rlSrc, r0);
2967 clobberReg(cUnit, r0);
2968 if ((dalvikOpCode == OP_DIV_INT_LIT8) ||
2969 (dalvikOpCode == OP_DIV_INT_LIT16)) {
2970 loadConstant(cUnit, r2, (int)__aeabi_idiv);
2971 isDiv = true;
2972 } else {
2973 loadConstant(cUnit, r2, (int)__aeabi_idivmod);
2974 isDiv = false;
2975 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07002976 loadConstant(cUnit, r1, lit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002977 opReg(cUnit, kOpBlx, r2);
2978 clobberCallRegs(cUnit);
2979 if (isDiv)
2980 rlResult = getReturnLoc(cUnit);
2981 else
2982 rlResult = getReturnLocAlt(cUnit);
2983 storeValue(cUnit, rlDest, rlResult);
2984 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002985 break;
2986 default:
2987 return true;
2988 }
Bill Buzbee1465db52009-09-23 17:17:35 -07002989 rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
2990 rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
2991 // Avoid shifts by literal 0 - no support in Thumb. Change to copy
2992 if (shiftOp && (lit == 0)) {
2993 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
2994 } else {
2995 opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
2996 }
2997 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002998 return false;
2999}
3000
3001static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
3002{
3003 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3004 int fieldOffset;
3005
3006 if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
3007 InstField *pInstField = (InstField *)
3008 cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003009
3010 assert(pInstField != NULL);
3011 fieldOffset = pInstField->byteOffset;
3012 } else {
Ben Chenga0e7b602009-10-13 23:09:01 -07003013 /* Deliberately break the code while make the compiler happy */
3014 fieldOffset = -1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003015 }
3016 switch (dalvikOpCode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07003017 case OP_NEW_ARRAY: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003018 // Generates a call - use explicit registers
3019 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3020 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
3021 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003022 void *classPtr = (void*)
3023 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
3024 assert(classPtr != NULL);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003025 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003026 genExportPC(cUnit, mir);
3027 loadValueDirectFixed(cUnit, rlSrc, r1); /* Len */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003028 loadConstant(cUnit, r0, (int) classPtr );
Bill Buzbee1465db52009-09-23 17:17:35 -07003029 loadConstant(cUnit, r3, (int)dvmAllocArrayByClass);
Ben Cheng4f489172009-09-27 17:08:35 -07003030 /*
3031 * "len < 0": bail to the interpreter to re-execute the
3032 * instruction
3033 */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003034 ArmLIR *pcrLabel =
Bill Buzbee1465db52009-09-23 17:17:35 -07003035 genRegImmCheck(cUnit, kArmCondMi, r1, 0, mir->offset, NULL);
Bill Buzbee270c1d62009-08-13 16:58:07 -07003036 loadConstant(cUnit, r2, ALLOC_DONT_TRACK);
Bill Buzbee1465db52009-09-23 17:17:35 -07003037 opReg(cUnit, kOpBlx, r3);
3038 clobberCallRegs(cUnit);
Ben Cheng4f489172009-09-27 17:08:35 -07003039 /* generate a branch over if allocation is successful */
Bill Buzbee1465db52009-09-23 17:17:35 -07003040 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3041 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
Ben Cheng4f489172009-09-27 17:08:35 -07003042 /*
3043 * OOM exception needs to be thrown here and cannot re-execute
3044 */
3045 loadConstant(cUnit, r0,
3046 (int) (cUnit->method->insns + mir->offset));
3047 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3048 /* noreturn */
3049
Bill Buzbee1465db52009-09-23 17:17:35 -07003050 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Cheng4f489172009-09-27 17:08:35 -07003051 target->defMask = ENCODE_ALL;
3052 branchOver->generic.target = (LIR *) target;
Bill Buzbee1465db52009-09-23 17:17:35 -07003053 rlResult = getReturnLoc(cUnit);
3054 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003055 break;
3056 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003057 case OP_INSTANCE_OF: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003058 // May generate a call - use explicit registers
3059 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3060 RegLocation rlDest = getDestLoc(cUnit, mir, 0);
3061 RegLocation rlResult;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003062 ClassObject *classPtr =
3063 (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
3064 assert(classPtr != NULL);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003065 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003066 loadValueDirectFixed(cUnit, rlSrc, r0); /* Ref */
Ben Chengba4fc8b2009-06-01 13:00:29 -07003067 loadConstant(cUnit, r2, (int) classPtr );
Bill Buzbee270c1d62009-08-13 16:58:07 -07003068//TUNING: compare to 0 primative to allow use of CB[N]Z
Bill Buzbee1465db52009-09-23 17:17:35 -07003069 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
Ben Cheng752c7942009-06-22 10:50:07 -07003070 /* When taken r0 has NULL which can be used for store directly */
Bill Buzbee1465db52009-09-23 17:17:35 -07003071 ArmLIR *branch1 = opCondBranch(cUnit, kArmCondEq);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003072 /* r1 now contains object->clazz */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003073 loadWordDisp(cUnit, r0, offsetof(Object, clazz), r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07003074 /* r1 now contains object->clazz */
3075 loadConstant(cUnit, r3, (int)dvmInstanceofNonTrivial);
Ben Cheng752c7942009-06-22 10:50:07 -07003076 loadConstant(cUnit, r0, 1); /* Assume true */
Bill Buzbee1465db52009-09-23 17:17:35 -07003077 opRegReg(cUnit, kOpCmp, r1, r2);
3078 ArmLIR *branch2 = opCondBranch(cUnit, kArmCondEq);
3079 genRegCopy(cUnit, r0, r1);
3080 genRegCopy(cUnit, r1, r2);
3081 opReg(cUnit, kOpBlx, r3);
3082 clobberCallRegs(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003083 /* branch target here */
Bill Buzbee1465db52009-09-23 17:17:35 -07003084 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
Ben Chengd7d426a2009-09-22 11:23:36 -07003085 target->defMask = ENCODE_ALL;
Bill Buzbee1465db52009-09-23 17:17:35 -07003086 rlResult = getReturnLoc(cUnit);
3087 storeValue(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003088 branch1->generic.target = (LIR *)target;
3089 branch2->generic.target = (LIR *)target;
3090 break;
3091 }
3092 case OP_IGET_WIDE:
3093 genIGetWide(cUnit, mir, fieldOffset);
3094 break;
3095 case OP_IGET:
3096 case OP_IGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003097 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003098 break;
3099 case OP_IGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003100 genIGet(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003101 break;
3102 case OP_IGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003103 genIGet(cUnit, mir, kSignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003104 break;
3105 case OP_IGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003106 genIGet(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003107 break;
3108 case OP_IGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003109 genIGet(cUnit, mir, kSignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003110 break;
3111 case OP_IPUT_WIDE:
3112 genIPutWide(cUnit, mir, fieldOffset);
3113 break;
3114 case OP_IPUT:
3115 case OP_IPUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003116 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003117 break;
3118 case OP_IPUT_SHORT:
3119 case OP_IPUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003120 genIPut(cUnit, mir, kUnsignedHalf, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003121 break;
3122 case OP_IPUT_BYTE:
3123 case OP_IPUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003124 genIPut(cUnit, mir, kUnsignedByte, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003125 break;
3126 default:
3127 return true;
3128 }
3129 return false;
3130}
3131
3132static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
3133{
3134 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3135 int fieldOffset = mir->dalvikInsn.vC;
3136 switch (dalvikOpCode) {
3137 case OP_IGET_QUICK:
3138 case OP_IGET_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07003139 genIGet(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003140 break;
3141 case OP_IPUT_QUICK:
3142 case OP_IPUT_OBJECT_QUICK:
Bill Buzbee1465db52009-09-23 17:17:35 -07003143 genIPut(cUnit, mir, kWord, fieldOffset);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003144 break;
3145 case OP_IGET_WIDE_QUICK:
3146 genIGetWide(cUnit, mir, fieldOffset);
3147 break;
3148 case OP_IPUT_WIDE_QUICK:
3149 genIPutWide(cUnit, mir, fieldOffset);
3150 break;
3151 default:
3152 return true;
3153 }
3154 return false;
3155
3156}
3157
3158/* Compare agaist zero */
3159static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003160 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003161{
3162 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003163 ArmConditionCode cond;
Bill Buzbee1465db52009-09-23 17:17:35 -07003164 RegLocation rlSrc1 = getSrcLoc(cUnit, mir, 0);
3165 RegLocation rlSrc2 = getSrcLoc(cUnit, mir, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003166
Bill Buzbee1465db52009-09-23 17:17:35 -07003167 rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
3168 rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
3169 opRegReg(cUnit, kOpCmp, rlSrc1.lowReg, rlSrc2.lowReg);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003170
3171 switch (dalvikOpCode) {
3172 case OP_IF_EQ:
Bill Buzbee1465db52009-09-23 17:17:35 -07003173 cond = kArmCondEq;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003174 break;
3175 case OP_IF_NE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003176 cond = kArmCondNe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003177 break;
3178 case OP_IF_LT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003179 cond = kArmCondLt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003180 break;
3181 case OP_IF_GE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003182 cond = kArmCondGe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003183 break;
3184 case OP_IF_GT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003185 cond = kArmCondGt;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003186 break;
3187 case OP_IF_LE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003188 cond = kArmCondLe;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003189 break;
3190 default:
3191 cond = 0;
3192 LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
3193 dvmAbort();
3194 }
3195 genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
3196 /* This mostly likely will be optimized away in a later phase */
3197 genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
3198 return false;
3199}
3200
3201static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
3202{
3203 OpCode opCode = mir->dalvikInsn.opCode;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003204
3205 switch (opCode) {
3206 case OP_MOVE_16:
3207 case OP_MOVE_OBJECT_16:
3208 case OP_MOVE_FROM16:
Ben Chenge9695e52009-06-16 16:11:47 -07003209 case OP_MOVE_OBJECT_FROM16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003210 storeValue(cUnit, getDestLoc(cUnit, mir, 0),
3211 getSrcLoc(cUnit, mir, 0));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003212 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003213 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003214 case OP_MOVE_WIDE_16:
Ben Chenge9695e52009-06-16 16:11:47 -07003215 case OP_MOVE_WIDE_FROM16: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003216 storeValueWide(cUnit, getDestLocWide(cUnit, mir, 0, 1),
3217 getSrcLocWide(cUnit, mir, 0, 1));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003218 break;
Ben Chenge9695e52009-06-16 16:11:47 -07003219 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003220 default:
3221 return true;
3222 }
3223 return false;
3224}
3225
3226static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
3227{
3228 OpCode opCode = mir->dalvikInsn.opCode;
Bill Buzbee1465db52009-09-23 17:17:35 -07003229 RegLocation rlSrc1;
3230 RegLocation rlSrc2;
3231 RegLocation rlDest;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003232
3233 if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003234 return handleArithOp( cUnit, mir );
Ben Chengba4fc8b2009-06-01 13:00:29 -07003235 }
3236
Bill Buzbee1465db52009-09-23 17:17:35 -07003237 /* APUTs have 3 sources and no targets */
3238 if (mir->ssaRep->numDefs == 0) {
3239 if (mir->ssaRep->numUses == 3) {
3240 rlDest = getSrcLoc(cUnit, mir, 0);
3241 rlSrc1 = getSrcLoc(cUnit, mir, 1);
3242 rlSrc2 = getSrcLoc(cUnit, mir, 2);
3243 } else {
3244 assert(mir->ssaRep->numUses == 4);
3245 rlDest = getSrcLocWide(cUnit, mir, 0, 1);
3246 rlSrc1 = getSrcLoc(cUnit, mir, 2);
3247 rlSrc2 = getSrcLoc(cUnit, mir, 3);
3248 }
3249 } else {
3250 /* Two sources and 1 dest. Deduce the operand sizes */
3251 if (mir->ssaRep->numUses == 4) {
3252 rlSrc1 = getSrcLocWide(cUnit, mir, 0, 1);
3253 rlSrc2 = getSrcLocWide(cUnit, mir, 2, 3);
3254 } else {
3255 assert(mir->ssaRep->numUses == 2);
3256 rlSrc1 = getSrcLoc(cUnit, mir, 0);
3257 rlSrc2 = getSrcLoc(cUnit, mir, 1);
3258 }
3259 if (mir->ssaRep->numDefs == 2) {
3260 rlDest = getDestLocWide(cUnit, mir, 0, 1);
3261 } else {
3262 assert(mir->ssaRep->numDefs == 1);
3263 rlDest = getDestLoc(cUnit, mir, 0);
3264 }
3265 }
3266
3267
Ben Chengba4fc8b2009-06-01 13:00:29 -07003268 switch (opCode) {
Bill Buzbeed45ba372009-06-15 17:00:57 -07003269 case OP_CMPL_FLOAT:
3270 case OP_CMPG_FLOAT:
3271 case OP_CMPL_DOUBLE:
3272 case OP_CMPG_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003273 return handleCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003274 case OP_CMP_LONG:
Bill Buzbee1465db52009-09-23 17:17:35 -07003275 genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003276 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003277 case OP_AGET_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003278 genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003279 break;
3280 case OP_AGET:
3281 case OP_AGET_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003282 genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003283 break;
3284 case OP_AGET_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003285 genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003286 break;
3287 case OP_AGET_BYTE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003288 genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003289 break;
3290 case OP_AGET_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003291 genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003292 break;
3293 case OP_AGET_SHORT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003294 genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003295 break;
3296 case OP_APUT_WIDE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003297 genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003298 break;
3299 case OP_APUT:
3300 case OP_APUT_OBJECT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003301 genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003302 break;
3303 case OP_APUT_SHORT:
3304 case OP_APUT_CHAR:
Bill Buzbee1465db52009-09-23 17:17:35 -07003305 genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003306 break;
3307 case OP_APUT_BYTE:
3308 case OP_APUT_BOOLEAN:
Bill Buzbee1465db52009-09-23 17:17:35 -07003309 genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003310 break;
3311 default:
3312 return true;
3313 }
3314 return false;
3315}
3316
Ben Cheng6c10a972009-10-29 14:39:18 -07003317/*
3318 * Find the matching case.
3319 *
3320 * return values:
3321 * r0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
3322 * including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
3323 * r1 (high 32-bit): the branch offset of the matching case (only for indexes
3324 * above MAX_CHAINED_SWITCH_CASES).
3325 *
3326 * Instructions around the call are:
3327 *
3328 * mov r2, pc
3329 * blx &findPackedSwitchIndex
3330 * mov pc, r0
3331 * .align4
3332 * chaining cell for case 0 [8 bytes]
3333 * chaining cell for case 1 [8 bytes]
3334 * :
3335 * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [8 bytes]
3336 * chaining cell for case default [8 bytes]
3337 * noChain exit
3338 */
3339s8 findPackedSwitchIndex(const u2* switchData, int testVal, int pc)
3340{
3341 int size;
3342 int firstKey;
3343 const int *entries;
3344 int index;
3345 int jumpIndex;
3346 int caseDPCOffset = 0;
3347 /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
3348 int chainingPC = (pc + 4) & ~3;
3349
3350 /*
3351 * Packed switch data format:
3352 * ushort ident = 0x0100 magic value
3353 * ushort size number of entries in the table
3354 * int first_key first (and lowest) switch case value
3355 * int targets[size] branch targets, relative to switch opcode
3356 *
3357 * Total size is (4+size*2) 16-bit code units.
3358 */
3359 size = switchData[1];
3360 assert(size > 0);
3361
3362 firstKey = switchData[2];
3363 firstKey |= switchData[3] << 16;
3364
3365
3366 /* The entries are guaranteed to be aligned on a 32-bit boundary;
3367 * we can treat them as a native int array.
3368 */
3369 entries = (const int*) &switchData[4];
3370 assert(((u4)entries & 0x3) == 0);
3371
3372 index = testVal - firstKey;
3373
3374 /* Jump to the default cell */
3375 if (index < 0 || index >= size) {
3376 jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
3377 /* Jump to the non-chaining exit point */
3378 } else if (index >= MAX_CHAINED_SWITCH_CASES) {
3379 jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
3380 caseDPCOffset = entries[index];
3381 /* Jump to the inline chaining cell */
3382 } else {
3383 jumpIndex = index;
3384 }
3385
3386 chainingPC += jumpIndex * 8;
3387 return (((s8) caseDPCOffset) << 32) | (u8) chainingPC;
3388}
3389
3390/* See comments for findPackedSwitchIndex */
3391s8 findSparseSwitchIndex(const u2* switchData, int testVal, int pc)
3392{
3393 int size;
3394 const int *keys;
3395 const int *entries;
3396 int chainingPC = (pc + 4) & ~3;
3397 int i;
3398
3399 /*
3400 * Sparse switch data format:
3401 * ushort ident = 0x0200 magic value
3402 * ushort size number of entries in the table; > 0
3403 * int keys[size] keys, sorted low-to-high; 32-bit aligned
3404 * int targets[size] branch targets, relative to switch opcode
3405 *
3406 * Total size is (2+size*4) 16-bit code units.
3407 */
3408
3409 size = switchData[1];
3410 assert(size > 0);
3411
3412 /* The keys are guaranteed to be aligned on a 32-bit boundary;
3413 * we can treat them as a native int array.
3414 */
3415 keys = (const int*) &switchData[2];
3416 assert(((u4)keys & 0x3) == 0);
3417
3418 /* The entries are guaranteed to be aligned on a 32-bit boundary;
3419 * we can treat them as a native int array.
3420 */
3421 entries = keys + size;
3422 assert(((u4)entries & 0x3) == 0);
3423
3424 /*
3425 * Run through the list of keys, which are guaranteed to
3426 * be sorted low-to-high.
3427 *
3428 * Most tables have 3-4 entries. Few have more than 10. A binary
3429 * search here is probably not useful.
3430 */
3431 for (i = 0; i < size; i++) {
3432 int k = keys[i];
3433 if (k == testVal) {
3434 /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
3435 int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
3436 i : MAX_CHAINED_SWITCH_CASES + 1;
3437 chainingPC += jumpIndex * 8;
3438 return (((s8) entries[i]) << 32) | (u8) chainingPC;
3439 } else if (k > testVal) {
3440 break;
3441 }
3442 }
3443 return chainingPC + MIN(size, MAX_CHAINED_SWITCH_CASES) * 8;
3444}
3445
Ben Chengba4fc8b2009-06-01 13:00:29 -07003446static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
3447{
3448 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
3449 switch (dalvikOpCode) {
3450 case OP_FILL_ARRAY_DATA: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003451 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
3452 // Making a call - use explicit registers
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003453 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003454 genExportPC(cUnit, mir);
3455 loadValueDirectFixed(cUnit, rlSrc, r0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003456 loadConstant(cUnit, r2, (int)dvmInterpHandleFillArrayData);
Ben Cheng6c10a972009-10-29 14:39:18 -07003457 loadConstant(cUnit, r1,
3458 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
Bill Buzbee1465db52009-09-23 17:17:35 -07003459 opReg(cUnit, kOpBlx, r2);
3460 clobberCallRegs(cUnit);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003461 /* generate a branch over if successful */
3462 opRegImm(cUnit, kOpCmp, r0, 0); /* NULL? */
3463 ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
3464 loadConstant(cUnit, r0,
3465 (int) (cUnit->method->insns + mir->offset));
3466 genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
3467 ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
3468 target->defMask = ENCODE_ALL;
3469 branchOver->generic.target = (LIR *) target;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003470 break;
3471 }
3472 /*
Ben Cheng6c10a972009-10-29 14:39:18 -07003473 * Compute the goto target of up to
3474 * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
3475 * See the comment before findPackedSwitchIndex for the code layout.
Ben Chengba4fc8b2009-06-01 13:00:29 -07003476 */
3477 case OP_PACKED_SWITCH:
3478 case OP_SPARSE_SWITCH: {
Bill Buzbee1465db52009-09-23 17:17:35 -07003479 RegLocation rlSrc = getSrcLoc(cUnit, mir, 0);
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003480 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003481 loadValueDirectFixed(cUnit, rlSrc, r1);
3482 lockAllTemps(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07003483 const u2 *switchData =
3484 cUnit->method->insns + mir->offset + mir->dalvikInsn.vB;
3485 u2 size = switchData[1];
3486
Ben Chengba4fc8b2009-06-01 13:00:29 -07003487 if (dalvikOpCode == OP_PACKED_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -07003488 loadConstant(cUnit, r4PC, (int)findPackedSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003489 } else {
Ben Cheng6c10a972009-10-29 14:39:18 -07003490 loadConstant(cUnit, r4PC, (int)findSparseSwitchIndex);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003491 }
Ben Cheng6c10a972009-10-29 14:39:18 -07003492 /* r0 <- Addr of the switch data */
3493 loadConstant(cUnit, r0,
3494 (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
3495 /* r2 <- pc of the instruction following the blx */
3496 opRegReg(cUnit, kOpMov, r2, rpc);
Bill Buzbee1465db52009-09-23 17:17:35 -07003497 opReg(cUnit, kOpBlx, r4PC);
3498 clobberCallRegs(cUnit);
Ben Cheng6c10a972009-10-29 14:39:18 -07003499 /* pc <- computed goto target */
3500 opRegReg(cUnit, kOpMov, rpc, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003501 break;
3502 }
3503 default:
3504 return true;
3505 }
3506 return false;
3507}
3508
3509static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003510 ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003511{
Bill Buzbee9bc3df32009-07-30 10:52:29 -07003512 ArmLIR *retChainingCell = NULL;
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003513 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003514
Bill Buzbeef4ce16f2009-07-28 13:28:25 -07003515 if (bb->fallThrough != NULL)
3516 retChainingCell = &labelList[bb->fallThrough->id];
3517
Ben Chengba4fc8b2009-06-01 13:00:29 -07003518 DecodedInstruction *dInsn = &mir->dalvikInsn;
3519 switch (mir->dalvikInsn.opCode) {
3520 /*
3521 * calleeMethod = this->clazz->vtable[
3522 * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
3523 * ]
3524 */
3525 case OP_INVOKE_VIRTUAL:
3526 case OP_INVOKE_VIRTUAL_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003527 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003528 int methodIndex =
3529 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
3530 methodIndex;
3531
3532 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
3533 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3534 else
3535 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3536
Ben Cheng38329f52009-07-07 14:19:20 -07003537 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3538 retChainingCell,
3539 predChainingCell,
3540 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003541 break;
3542 }
3543 /*
3544 * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
3545 * ->pResMethods[BBBB]->methodIndex]
3546 */
3547 /* TODO - not excersized in RunPerf.jar */
3548 case OP_INVOKE_SUPER:
3549 case OP_INVOKE_SUPER_RANGE: {
3550 int mIndex = cUnit->method->clazz->pDvmDex->
3551 pResMethods[dInsn->vB]->methodIndex;
3552 const Method *calleeMethod =
3553 cUnit->method->clazz->super->vtable[mIndex];
3554
3555 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
3556 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3557 else
3558 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3559
3560 /* r0 = calleeMethod */
3561 loadConstant(cUnit, r0, (int) calleeMethod);
3562
Ben Cheng38329f52009-07-07 14:19:20 -07003563 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3564 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003565 break;
3566 }
3567 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3568 case OP_INVOKE_DIRECT:
3569 case OP_INVOKE_DIRECT_RANGE: {
3570 const Method *calleeMethod =
3571 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3572
3573 if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
3574 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3575 else
3576 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3577
3578 /* r0 = calleeMethod */
3579 loadConstant(cUnit, r0, (int) calleeMethod);
3580
Ben Cheng38329f52009-07-07 14:19:20 -07003581 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3582 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003583 break;
3584 }
3585 /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
3586 case OP_INVOKE_STATIC:
3587 case OP_INVOKE_STATIC_RANGE: {
3588 const Method *calleeMethod =
3589 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB];
3590
3591 if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
3592 genProcessArgsNoRange(cUnit, mir, dInsn,
3593 NULL /* no null check */);
3594 else
3595 genProcessArgsRange(cUnit, mir, dInsn,
3596 NULL /* no null check */);
3597
3598 /* r0 = calleeMethod */
3599 loadConstant(cUnit, r0, (int) calleeMethod);
3600
Ben Cheng38329f52009-07-07 14:19:20 -07003601 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3602 calleeMethod);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003603 break;
3604 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003605 /*
Ben Chengba4fc8b2009-06-01 13:00:29 -07003606 * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
3607 * BBBB, method, method->clazz->pDvmDex)
Ben Cheng38329f52009-07-07 14:19:20 -07003608 *
3609 * Given "invoke-interface {v0}", the following is the generated code:
3610 *
3611 * 0x426a9abe : ldr r0, [r5, #0] --+
3612 * 0x426a9ac0 : mov r7, r5 |
3613 * 0x426a9ac2 : sub r7, #24 |
3614 * 0x426a9ac4 : cmp r0, #0 | genProcessArgsNoRange
3615 * 0x426a9ac6 : beq 0x426a9afe |
3616 * 0x426a9ac8 : stmia r7, <r0> --+
3617 * 0x426a9aca : ldr r4, [pc, #104] --> r4 <- dalvikPC of this invoke
3618 * 0x426a9acc : add r1, pc, #52 --> r1 <- &retChainingCell
3619 * 0x426a9ace : add r2, pc, #60 --> r2 <- &predictedChainingCell
3620 * 0x426a9ad0 : blx_1 0x426a918c --+ TEMPLATE_INVOKE_METHOD_
3621 * 0x426a9ad2 : blx_2 see above --+ PREDICTED_CHAIN
3622 * 0x426a9ad4 : b 0x426a9b0c --> off to the predicted chain
3623 * 0x426a9ad6 : b 0x426a9afe --> punt to the interpreter
Ben Chenga8e64a72009-10-20 13:01:36 -07003624 * 0x426a9ad8 : mov r8, r1 --+
3625 * 0x426a9ada : mov r9, r2 |
3626 * 0x426a9adc : mov r10, r3 |
Ben Cheng38329f52009-07-07 14:19:20 -07003627 * 0x426a9ade : mov r0, r3 |
3628 * 0x426a9ae0 : mov r1, #74 | dvmFindInterfaceMethodInCache
3629 * 0x426a9ae2 : ldr r2, [pc, #76] |
3630 * 0x426a9ae4 : ldr r3, [pc, #68] |
3631 * 0x426a9ae6 : ldr r7, [pc, #64] |
3632 * 0x426a9ae8 : blx r7 --+
Ben Chenga8e64a72009-10-20 13:01:36 -07003633 * 0x426a9aea : mov r1, r8 --> r1 <- rechain count
Ben Cheng38329f52009-07-07 14:19:20 -07003634 * 0x426a9aec : cmp r1, #0 --> compare against 0
3635 * 0x426a9aee : bgt 0x426a9af8 --> >=0? don't rechain
3636 * 0x426a9af0 : ldr r7, [r6, #96] --+
Ben Chenga8e64a72009-10-20 13:01:36 -07003637 * 0x426a9af2 : mov r2, r9 | dvmJitToPatchPredictedChain
3638 * 0x426a9af4 : mov r3, r10 |
Ben Cheng38329f52009-07-07 14:19:20 -07003639 * 0x426a9af6 : blx r7 --+
3640 * 0x426a9af8 : add r1, pc, #8 --> r1 <- &retChainingCell
3641 * 0x426a9afa : blx_1 0x426a9098 --+ TEMPLATE_INVOKE_METHOD_NO_OPT
3642 * 0x426a9afc : blx_2 see above --+
3643 * -------- reconstruct dalvik PC : 0x428b786c @ +0x001e
3644 * 0x426a9afe (0042): ldr r0, [pc, #52]
3645 * Exception_Handling:
3646 * 0x426a9b00 (0044): ldr r1, [r6, #84]
3647 * 0x426a9b02 (0046): blx r1
3648 * 0x426a9b04 (0048): .align4
3649 * -------- chaining cell (hot): 0x0021
3650 * 0x426a9b04 (0048): ldr r0, [r6, #92]
3651 * 0x426a9b06 (004a): blx r0
3652 * 0x426a9b08 (004c): data 0x7872(30834)
3653 * 0x426a9b0a (004e): data 0x428b(17035)
3654 * 0x426a9b0c (0050): .align4
3655 * -------- chaining cell (predicted)
3656 * 0x426a9b0c (0050): data 0x0000(0) --> will be patched into bx
3657 * 0x426a9b0e (0052): data 0x0000(0)
3658 * 0x426a9b10 (0054): data 0x0000(0) --> class
3659 * 0x426a9b12 (0056): data 0x0000(0)
3660 * 0x426a9b14 (0058): data 0x0000(0) --> method
3661 * 0x426a9b16 (005a): data 0x0000(0)
3662 * 0x426a9b18 (005c): data 0x0000(0) --> reset count
3663 * 0x426a9b1a (005e): data 0x0000(0)
3664 * 0x426a9b28 (006c): .word (0xad0392a5)
3665 * 0x426a9b2c (0070): .word (0x6e750)
3666 * 0x426a9b30 (0074): .word (0x4109a618)
3667 * 0x426a9b34 (0078): .word (0x428b786c)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003668 */
3669 case OP_INVOKE_INTERFACE:
3670 case OP_INVOKE_INTERFACE_RANGE: {
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003671 ArmLIR *predChainingCell = &labelList[bb->taken->id];
Ben Chengba4fc8b2009-06-01 13:00:29 -07003672 int methodIndex = dInsn->vB;
3673
Bill Buzbee1465db52009-09-23 17:17:35 -07003674 /* Ensure that nothing is both live and dirty */
3675 flushAllRegs(cUnit);
3676
Ben Chengba4fc8b2009-06-01 13:00:29 -07003677 if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
3678 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3679 else
3680 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3681
Ben Cheng38329f52009-07-07 14:19:20 -07003682 /* "this" is already left in r0 by genProcessArgs* */
3683
3684 /* r4PC = dalvikCallsite */
3685 loadConstant(cUnit, r4PC,
3686 (int) (cUnit->method->insns + mir->offset));
3687
3688 /* r1 = &retChainingCell */
Bill Buzbee270c1d62009-08-13 16:58:07 -07003689 ArmLIR *addrRetChain =
Bill Buzbee1465db52009-09-23 17:17:35 -07003690 opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003691 addrRetChain->generic.target = (LIR *) retChainingCell;
3692
3693 /* r2 = &predictedChainingCell */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003694 ArmLIR *predictedChainingCell =
Bill Buzbee1465db52009-09-23 17:17:35 -07003695 opRegRegImm(cUnit, kOpAdd, r2, rpc, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003696 predictedChainingCell->generic.target = (LIR *) predChainingCell;
3697
3698 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
3699
3700 /* return through lr - jump to the chaining cell */
3701 genUnconditionalBranch(cUnit, predChainingCell);
3702
3703 /*
3704 * null-check on "this" may have been eliminated, but we still need
3705 * a PC-reconstruction label for stack overflow bailout.
3706 */
3707 if (pcrLabel == NULL) {
3708 int dPC = (int) (cUnit->method->insns + mir->offset);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003709 pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07003710 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng38329f52009-07-07 14:19:20 -07003711 pcrLabel->operands[0] = dPC;
3712 pcrLabel->operands[1] = mir->offset;
3713 /* Insert the place holder to the growable list */
3714 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
3715 }
3716
3717 /* return through lr+2 - punt to the interpreter */
3718 genUnconditionalBranch(cUnit, pcrLabel);
3719
3720 /*
3721 * return through lr+4 - fully resolve the callee method.
3722 * r1 <- count
3723 * r2 <- &predictedChainCell
3724 * r3 <- this->class
3725 * r4 <- dPC
3726 * r7 <- this->class->vtable
3727 */
3728
3729 /* Save count, &predictedChainCell, and class to high regs first */
Bill Buzbee1465db52009-09-23 17:17:35 -07003730 genRegCopy(cUnit, r8, r1);
3731 genRegCopy(cUnit, r9, r2);
3732 genRegCopy(cUnit, r10, r3);
Ben Cheng38329f52009-07-07 14:19:20 -07003733
Ben Chengba4fc8b2009-06-01 13:00:29 -07003734 /* r0 now contains this->clazz */
Bill Buzbee1465db52009-09-23 17:17:35 -07003735 genRegCopy(cUnit, r0, r3);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003736
3737 /* r1 = BBBB */
3738 loadConstant(cUnit, r1, dInsn->vB);
3739
3740 /* r2 = method (caller) */
3741 loadConstant(cUnit, r2, (int) cUnit->method);
3742
3743 /* r3 = pDvmDex */
3744 loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
3745
3746 loadConstant(cUnit, r7,
3747 (intptr_t) dvmFindInterfaceMethodInCache);
Bill Buzbee1465db52009-09-23 17:17:35 -07003748 opReg(cUnit, kOpBlx, r7);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003749
3750 /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
3751
Bill Buzbee1465db52009-09-23 17:17:35 -07003752 genRegCopy(cUnit, r1, r8);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003753
Ben Cheng38329f52009-07-07 14:19:20 -07003754 /* Check if rechain limit is reached */
Bill Buzbee1465db52009-09-23 17:17:35 -07003755 opRegImm(cUnit, kOpCmp, r1, 0);
Ben Cheng38329f52009-07-07 14:19:20 -07003756
Bill Buzbee1465db52009-09-23 17:17:35 -07003757 ArmLIR *bypassRechaining = opCondBranch(cUnit, kArmCondGt);
Ben Cheng38329f52009-07-07 14:19:20 -07003758
Bill Buzbee270c1d62009-08-13 16:58:07 -07003759 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
3760 jitToInterpEntries.dvmJitToPatchPredictedChain), r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003761
Bill Buzbee1465db52009-09-23 17:17:35 -07003762 genRegCopy(cUnit, r2, r9);
3763 genRegCopy(cUnit, r3, r10);
Ben Cheng38329f52009-07-07 14:19:20 -07003764
3765 /*
3766 * r0 = calleeMethod
3767 * r2 = &predictedChainingCell
3768 * r3 = class
3769 *
3770 * &returnChainingCell has been loaded into r1 but is not needed
3771 * when patching the chaining cell and will be clobbered upon
3772 * returning so it will be reconstructed again.
3773 */
Bill Buzbee1465db52009-09-23 17:17:35 -07003774 opReg(cUnit, kOpBlx, r7);
Ben Cheng38329f52009-07-07 14:19:20 -07003775
3776 /* r1 = &retChainingCell */
Bill Buzbee1465db52009-09-23 17:17:35 -07003777 addrRetChain = opRegRegImm(cUnit, kOpAdd, r1, rpc, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003778 addrRetChain->generic.target = (LIR *) retChainingCell;
Ben Cheng38329f52009-07-07 14:19:20 -07003779
3780 bypassRechaining->generic.target = (LIR *) addrRetChain;
3781
Ben Chengba4fc8b2009-06-01 13:00:29 -07003782 /*
3783 * r0 = this, r1 = calleeMethod,
3784 * r1 = &ChainingCell,
3785 * r4PC = callsiteDPC,
3786 */
3787 genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
3788#if defined(INVOKE_STATS)
Ben Cheng38329f52009-07-07 14:19:20 -07003789 gDvmJit.invokePredictedChain++;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003790#endif
3791 /* Handle exceptions using the interpreter */
3792 genTrap(cUnit, mir->offset, pcrLabel);
3793 break;
3794 }
3795 /* NOP */
3796 case OP_INVOKE_DIRECT_EMPTY: {
3797 return false;
3798 }
3799 case OP_FILLED_NEW_ARRAY:
3800 case OP_FILLED_NEW_ARRAY_RANGE: {
3801 /* Just let the interpreter deal with these */
3802 genInterpSingleStep(cUnit, mir);
3803 break;
3804 }
3805 default:
3806 return true;
3807 }
3808 return false;
3809}
3810
3811static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003812 BasicBlock *bb, ArmLIR *labelList)
Ben Chengba4fc8b2009-06-01 13:00:29 -07003813{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07003814 ArmLIR *retChainingCell = &labelList[bb->fallThrough->id];
3815 ArmLIR *predChainingCell = &labelList[bb->taken->id];
3816 ArmLIR *pcrLabel = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07003817
3818 DecodedInstruction *dInsn = &mir->dalvikInsn;
3819 switch (mir->dalvikInsn.opCode) {
3820 /* calleeMethod = this->clazz->vtable[BBBB] */
3821 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3822 case OP_INVOKE_VIRTUAL_QUICK: {
3823 int methodIndex = dInsn->vB;
3824 if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
3825 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3826 else
3827 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3828
Ben Cheng38329f52009-07-07 14:19:20 -07003829 genInvokeVirtualCommon(cUnit, mir, methodIndex,
3830 retChainingCell,
3831 predChainingCell,
3832 pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003833 break;
3834 }
3835 /* calleeMethod = method->clazz->super->vtable[BBBB] */
3836 case OP_INVOKE_SUPER_QUICK:
3837 case OP_INVOKE_SUPER_QUICK_RANGE: {
3838 const Method *calleeMethod =
3839 cUnit->method->clazz->super->vtable[dInsn->vB];
3840
3841 if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
3842 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
3843 else
3844 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
3845
3846 /* r0 = calleeMethod */
3847 loadConstant(cUnit, r0, (int) calleeMethod);
3848
Ben Cheng38329f52009-07-07 14:19:20 -07003849 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
3850 calleeMethod);
3851 /* Handle exceptions using the interpreter */
3852 genTrap(cUnit, mir->offset, pcrLabel);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003853 break;
3854 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003855 default:
3856 return true;
3857 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07003858 return false;
3859}
3860
3861/*
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003862 * This operation is complex enough that we'll do it partly inline
3863 * and partly with a handler. NOTE: the handler uses hardcoded
3864 * values for string object offsets and must be revisitied if the
3865 * layout changes.
3866 */
3867static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
3868{
3869#if defined(USE_GLOBAL_STRING_DEFS)
3870 return false;
3871#else
3872 ArmLIR *rollback;
3873 RegLocation rlThis = getSrcLoc(cUnit, mir, 0);
3874 RegLocation rlComp = getSrcLoc(cUnit, mir, 1);
3875
3876 loadValueDirectFixed(cUnit, rlThis, r0);
3877 loadValueDirectFixed(cUnit, rlComp, r1);
3878 /* Test objects for NULL */
3879 rollback = genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3880 genNullCheck(cUnit, rlComp.sRegLow, r1, mir->offset, rollback);
3881 /*
3882 * TUNING: we could check for object pointer equality before invoking
3883 * handler. Unclear whether the gain would be worth the added code size
3884 * expansion.
3885 */
3886 genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
3887 storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit));
3888 return true;
3889#endif
3890}
3891
3892static bool genInlinedIndexOf(CompilationUnit *cUnit, MIR *mir, bool singleI)
3893{
3894#if defined(USE_GLOBAL_STRING_DEFS)
3895 return false;
3896#else
3897 RegLocation rlThis = getSrcLoc(cUnit, mir, 0);
3898 RegLocation rlChar = getSrcLoc(cUnit, mir, 1);
3899
3900 loadValueDirectFixed(cUnit, rlThis, r0);
3901 loadValueDirectFixed(cUnit, rlChar, r1);
3902 if (!singleI) {
3903 RegLocation rlStart = getSrcLoc(cUnit, mir, 2);
3904 loadValueDirectFixed(cUnit, rlStart, r2);
3905 } else {
3906 loadConstant(cUnit, r2, 0);
3907 }
3908 /* Test objects for NULL */
3909 genNullCheck(cUnit, rlThis.sRegLow, r0, mir->offset, NULL);
3910 genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
3911 storeValue(cUnit, inlinedTarget(cUnit, mir, false), getReturnLoc(cUnit));
3912 return true;
3913#endif
3914}
3915
3916
3917/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07003918 * NOTE: We assume here that the special native inline routines
3919 * are side-effect free. By making this assumption, we can safely
3920 * re-execute the routine from the interpreter if it decides it
3921 * wants to throw an exception. We still need to EXPORT_PC(), though.
3922 */
3923static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
3924{
3925 DecodedInstruction *dInsn = &mir->dalvikInsn;
3926 switch( mir->dalvikInsn.opCode) {
3927 case OP_EXECUTE_INLINE: {
3928 unsigned int i;
3929 const InlineOperation* inLineTable = dvmGetInlineOpsTable();
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003930 int offset = offsetof(InterpState, retval);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003931 int operation = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07003932 int tReg1;
3933 int tReg2;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003934 switch (operation) {
3935 case INLINE_EMPTYINLINEMETHOD:
3936 return false; /* Nop */
3937 case INLINE_STRING_LENGTH:
3938 return genInlinedStringLength(cUnit, mir);
3939 case INLINE_MATH_ABS_INT:
3940 return genInlinedAbsInt(cUnit, mir);
3941 case INLINE_MATH_ABS_LONG:
3942 return genInlinedAbsLong(cUnit, mir);
3943 case INLINE_MATH_MIN_INT:
3944 return genInlinedMinMaxInt(cUnit, mir, true);
3945 case INLINE_MATH_MAX_INT:
3946 return genInlinedMinMaxInt(cUnit, mir, false);
3947 case INLINE_STRING_CHARAT:
3948 return genInlinedStringCharAt(cUnit, mir);
3949 case INLINE_MATH_SQRT:
3950 if (genInlineSqrt(cUnit, mir))
Bill Buzbee9727c3d2009-08-01 11:32:36 -07003951 return false;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003952 else
3953 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003954 case INLINE_MATH_ABS_FLOAT:
Bill Buzbee1465db52009-09-23 17:17:35 -07003955 if (genInlinedAbsFloat(cUnit, mir))
3956 return false;
3957 else
3958 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003959 case INLINE_MATH_ABS_DOUBLE:
Bill Buzbee1465db52009-09-23 17:17:35 -07003960 if (genInlinedAbsDouble(cUnit, mir))
3961 return false;
3962 else
3963 break;
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003964 case INLINE_STRING_COMPARETO:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003965 if (genInlinedCompareTo(cUnit, mir))
3966 return false;
3967 else
3968 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003969 case INLINE_STRING_INDEXOF_I:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003970 if (genInlinedIndexOf(cUnit, mir, true /* I */))
3971 return false;
3972 else
3973 break;
Bill Buzbee12ba0152009-09-03 14:03:09 -07003974 case INLINE_STRING_INDEXOF_II:
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003975 if (genInlinedIndexOf(cUnit, mir, false /* I */))
3976 return false;
3977 else
3978 break;
3979 case INLINE_STRING_EQUALS:
3980 case INLINE_MATH_COS:
3981 case INLINE_MATH_SIN:
3982 break; /* Handle with C routine */
Bill Buzbee50a6bf22009-07-08 13:08:04 -07003983 default:
3984 dvmAbort();
Ben Chengba4fc8b2009-06-01 13:00:29 -07003985 }
Bill Buzbeefd023aa2009-11-02 09:23:49 -08003986 flushAllRegs(cUnit); /* Send everything to home location */
Bill Buzbee1465db52009-09-23 17:17:35 -07003987 clobberCallRegs(cUnit);
3988 clobberReg(cUnit, r4PC);
3989 clobberReg(cUnit, r7);
3990 opRegRegImm(cUnit, kOpAdd, r4PC, rGLUE, offset);
3991 opImm(cUnit, kOpPush, (1<<r4PC) | (1<<r7));
Ben Chengba4fc8b2009-06-01 13:00:29 -07003992 loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
Bill Buzbee1465db52009-09-23 17:17:35 -07003993 genExportPC(cUnit, mir);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003994 for (i=0; i < dInsn->vA; i++) {
Bill Buzbee1465db52009-09-23 17:17:35 -07003995 loadValueDirect(cUnit, getSrcLoc(cUnit, mir, i), i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07003996 }
Bill Buzbee1465db52009-09-23 17:17:35 -07003997 opReg(cUnit, kOpBlx, r4PC);
3998 opRegImm(cUnit, kOpAdd, r13, 8);
Ben Chenge9695e52009-06-16 16:11:47 -07003999 genZeroCheck(cUnit, r0, mir->offset, NULL);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004000 break;
4001 }
4002 default:
4003 return true;
4004 }
4005 return false;
4006}
4007
4008static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
4009{
Bill Buzbee1465db52009-09-23 17:17:35 -07004010 //TUNING: We're using core regs here - not optimal when target is a double
4011 RegLocation rlDest = getDestLocWide(cUnit, mir, 0, 1);
4012 RegLocation rlResult = evalLoc(cUnit, rlDest, kCoreReg, true);
4013 loadConstantValue(cUnit, rlResult.lowReg,
4014 mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
4015 loadConstantValue(cUnit, rlResult.highReg,
4016 (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
4017 storeValueWide(cUnit, rlDest, rlResult);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004018 return false;
4019}
4020
Ben Chengba4fc8b2009-06-01 13:00:29 -07004021/*
4022 * The following are special processing routines that handle transfer of
4023 * controls between compiled code and the interpreter. Certain VM states like
4024 * Dalvik PC and special-purpose registers are reconstructed here.
4025 */
4026
Ben Cheng1efc9c52009-06-08 18:25:27 -07004027/* Chaining cell for code that may need warmup. */
4028static void handleNormalChainingCell(CompilationUnit *cUnit,
4029 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004030{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004031 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4032 jitToInterpEntries.dvmJitToInterpNormal), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004033 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004034 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4035}
4036
4037/*
Ben Cheng1efc9c52009-06-08 18:25:27 -07004038 * Chaining cell for instructions that immediately following already translated
4039 * code.
Ben Chengba4fc8b2009-06-01 13:00:29 -07004040 */
Ben Cheng1efc9c52009-06-08 18:25:27 -07004041static void handleHotChainingCell(CompilationUnit *cUnit,
4042 unsigned int offset)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004043{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004044 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4045 jitToInterpEntries.dvmJitToTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004046 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004047 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4048}
4049
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004050#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Jeff Hao97319a82009-08-12 16:57:15 -07004051/* Chaining cell for branches that branch back into the same basic block */
4052static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
4053 unsigned int offset)
4054{
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004055#if defined(WITH_SELF_VERIFICATION)
Bill Buzbee1465db52009-09-23 17:17:35 -07004056 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Jeff Hao97319a82009-08-12 16:57:15 -07004057 offsetof(InterpState, jitToInterpEntries.dvmJitToBackwardBranch) >> 2);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004058#else
Bill Buzbee1465db52009-09-23 17:17:35 -07004059 newLIR3(cUnit, kThumbLdrRRI5, r0, rGLUE,
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004060 offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
4061#endif
Bill Buzbee1465db52009-09-23 17:17:35 -07004062 newLIR1(cUnit, kThumbBlxR, r0);
Jeff Hao97319a82009-08-12 16:57:15 -07004063 addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
4064}
4065
4066#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004067/* Chaining cell for monomorphic method invocations. */
Ben Cheng38329f52009-07-07 14:19:20 -07004068static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
4069 const Method *callee)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004070{
Bill Buzbee270c1d62009-08-13 16:58:07 -07004071 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4072 jitToInterpEntries.dvmJitToTraceSelect), r0);
Bill Buzbee1465db52009-09-23 17:17:35 -07004073 opReg(cUnit, kOpBlx, r0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004074 addWordData(cUnit, (int) (callee->insns), true);
4075}
4076
Ben Cheng38329f52009-07-07 14:19:20 -07004077/* Chaining cell for monomorphic method invocations. */
4078static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
4079{
4080
4081 /* Should not be executed in the initial state */
4082 addWordData(cUnit, PREDICTED_CHAIN_BX_PAIR_INIT, true);
4083 /* To be filled: class */
4084 addWordData(cUnit, PREDICTED_CHAIN_CLAZZ_INIT, true);
4085 /* To be filled: method */
4086 addWordData(cUnit, PREDICTED_CHAIN_METHOD_INIT, true);
4087 /*
4088 * Rechain count. The initial value of 0 here will trigger chaining upon
4089 * the first invocation of this callsite.
4090 */
4091 addWordData(cUnit, PREDICTED_CHAIN_COUNTER_INIT, true);
4092}
4093
Ben Chengba4fc8b2009-06-01 13:00:29 -07004094/* Load the Dalvik PC into r0 and jump to the specified target */
4095static void handlePCReconstruction(CompilationUnit *cUnit,
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004096 ArmLIR *targetLabel)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004097{
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004098 ArmLIR **pcrLabel =
4099 (ArmLIR **) cUnit->pcReconstructionList.elemList;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004100 int numElems = cUnit->pcReconstructionList.numUsed;
4101 int i;
4102 for (i = 0; i < numElems; i++) {
4103 dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
4104 /* r0 = dalvik PC */
4105 loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
4106 genUnconditionalBranch(cUnit, targetLabel);
4107 }
4108}
4109
Bill Buzbee1465db52009-09-23 17:17:35 -07004110static char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
4111 "kMirOpPhi",
4112 "kMirOpNullNRangeUpCheck",
4113 "kMirOpNullNRangeDownCheck",
4114 "kMirOpLowerBound",
4115 "kMirOpPunt",
Ben Cheng4238ec22009-08-24 16:32:22 -07004116};
4117
4118/*
4119 * vA = arrayReg;
4120 * vB = idxReg;
4121 * vC = endConditionReg;
4122 * arg[0] = maxC
4123 * arg[1] = minC
4124 * arg[2] = loopBranchConditionCode
4125 */
4126static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
4127{
Bill Buzbee1465db52009-09-23 17:17:35 -07004128 /*
4129 * NOTE: these synthesized blocks don't have ssa names assigned
4130 * for Dalvik registers. However, because they dominate the following
4131 * blocks we can simply use the Dalvik name w/ subscript 0 as the
4132 * ssa name.
4133 */
Ben Cheng4238ec22009-08-24 16:32:22 -07004134 DecodedInstruction *dInsn = &mir->dalvikInsn;
4135 const int lenOffset = offsetof(ArrayObject, length);
Ben Cheng4238ec22009-08-24 16:32:22 -07004136 const int maxC = dInsn->arg[0];
4137 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07004138 int regLength;
4139 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
4140 RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
Ben Cheng4238ec22009-08-24 16:32:22 -07004141
4142 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07004143 rlArray = loadValue(cUnit, rlArray, kCoreReg);
4144 rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
4145 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004146 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4147
4148 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07004149 regLength = allocTemp(cUnit);
4150 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07004151
4152 int delta = maxC;
4153 /*
4154 * If the loop end condition is ">=" instead of ">", then the largest value
4155 * of the index is "endCondition - 1".
4156 */
4157 if (dInsn->arg[2] == OP_IF_GE) {
4158 delta--;
4159 }
4160
4161 if (delta) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004162 int tReg = allocTemp(cUnit);
4163 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
4164 rlIdxEnd.lowReg = tReg;
4165 freeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004166 }
4167 /* Punt if "regIdxEnd < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004168 genRegRegCheck(cUnit, kArmCondGe, rlIdxEnd.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07004169 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004170}
4171
4172/*
4173 * vA = arrayReg;
4174 * vB = idxReg;
4175 * vC = endConditionReg;
4176 * arg[0] = maxC
4177 * arg[1] = minC
4178 * arg[2] = loopBranchConditionCode
4179 */
4180static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
4181{
4182 DecodedInstruction *dInsn = &mir->dalvikInsn;
4183 const int lenOffset = offsetof(ArrayObject, length);
Bill Buzbee1465db52009-09-23 17:17:35 -07004184 const int regLength = allocTemp(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -07004185 const int maxC = dInsn->arg[0];
4186 const int minC = dInsn->arg[1];
Bill Buzbee1465db52009-09-23 17:17:35 -07004187 RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
4188 RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
Ben Cheng4238ec22009-08-24 16:32:22 -07004189
4190 /* regArray <- arrayRef */
Bill Buzbee1465db52009-09-23 17:17:35 -07004191 rlArray = loadValue(cUnit, rlArray, kCoreReg);
4192 rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
4193 genRegImmCheck(cUnit, kArmCondEq, rlArray.lowReg, 0, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004194 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4195
4196 /* regLength <- len(arrayRef) */
Bill Buzbee1465db52009-09-23 17:17:35 -07004197 loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
Ben Cheng4238ec22009-08-24 16:32:22 -07004198
4199 if (maxC) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004200 int tReg = allocTemp(cUnit);
4201 opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
4202 rlIdxInit.lowReg = tReg;
4203 freeTemp(cUnit, tReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004204 }
4205
4206 /* Punt if "regIdxInit < len(Array)" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004207 genRegRegCheck(cUnit, kArmCondGe, rlIdxInit.lowReg, regLength, 0,
Ben Cheng0fd31e42009-09-03 14:40:16 -07004208 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004209}
4210
4211/*
4212 * vA = idxReg;
4213 * vB = minC;
4214 */
4215static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
4216{
4217 DecodedInstruction *dInsn = &mir->dalvikInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -07004218 const int minC = dInsn->vB;
Bill Buzbee1465db52009-09-23 17:17:35 -07004219 RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
Ben Cheng4238ec22009-08-24 16:32:22 -07004220
4221 /* regIdx <- initial index value */
Bill Buzbee1465db52009-09-23 17:17:35 -07004222 rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004223
4224 /* Punt if "regIdxInit + minC >= 0" is false */
Bill Buzbee1465db52009-09-23 17:17:35 -07004225 genRegImmCheck(cUnit, kArmCondLt, rlIdx.lowReg, -minC, 0,
Ben Cheng4238ec22009-08-24 16:32:22 -07004226 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4227}
4228
4229/* Extended MIR instructions like PHI */
4230static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
4231{
Bill Buzbee1465db52009-09-23 17:17:35 -07004232 int opOffset = mir->dalvikInsn.opCode - kMirOpFirst;
Ben Cheng4238ec22009-08-24 16:32:22 -07004233 char *msg = dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
4234 false);
4235 strcpy(msg, extendedMIROpNames[opOffset]);
Bill Buzbee1465db52009-09-23 17:17:35 -07004236 newLIR1(cUnit, kArmPseudoExtended, (int) msg);
Ben Cheng4238ec22009-08-24 16:32:22 -07004237
4238 switch (mir->dalvikInsn.opCode) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004239 case kMirOpPhi: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004240 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07004241 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07004242 break;
4243 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004244 case kMirOpNullNRangeUpCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004245 genHoistedChecksForCountUpLoop(cUnit, mir);
4246 break;
4247 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004248 case kMirOpNullNRangeDownCheck: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004249 genHoistedChecksForCountDownLoop(cUnit, mir);
4250 break;
4251 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004252 case kMirOpLowerBound: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004253 genHoistedLowerBoundCheck(cUnit, mir);
4254 break;
4255 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004256 case kMirOpPunt: {
Ben Cheng4238ec22009-08-24 16:32:22 -07004257 genUnconditionalBranch(cUnit,
4258 (ArmLIR *) cUnit->loopAnalysis->branchToPCR);
4259 break;
4260 }
4261 default:
4262 break;
4263 }
4264}
4265
4266/*
4267 * Create a PC-reconstruction cell for the starting offset of this trace.
4268 * Since the PCR cell is placed near the end of the compiled code which is
4269 * usually out of range for a conditional branch, we put two branches (one
4270 * branch over to the loop body and one layover branch to the actual PCR) at the
4271 * end of the entry block.
4272 */
4273static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
4274 ArmLIR *bodyLabel)
4275{
4276 /* Set up the place holder to reconstruct this Dalvik PC */
4277 ArmLIR *pcrLabel = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004278 pcrLabel->opCode = ARM_PSEUDO_kPCReconstruction_CELL;
Ben Cheng4238ec22009-08-24 16:32:22 -07004279 pcrLabel->operands[0] =
4280 (int) (cUnit->method->insns + entry->startOffset);
4281 pcrLabel->operands[1] = entry->startOffset;
4282 /* Insert the place holder to the growable list */
4283 dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
4284
4285 /*
4286 * Next, create two branches - one branch over to the loop body and the
4287 * other branch to the PCR cell to punt.
4288 */
4289 ArmLIR *branchToBody = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004290 branchToBody->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07004291 branchToBody->generic.target = (LIR *) bodyLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07004292 setupResourceMasks(branchToBody);
Ben Cheng4238ec22009-08-24 16:32:22 -07004293 cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
4294
4295 ArmLIR *branchToPCR = dvmCompilerNew(sizeof(ArmLIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004296 branchToPCR->opCode = kThumbBUncond;
Ben Cheng4238ec22009-08-24 16:32:22 -07004297 branchToPCR->generic.target = (LIR *) pcrLabel;
Ben Chengdcf3e5d2009-09-11 13:42:05 -07004298 setupResourceMasks(branchToPCR);
Ben Cheng4238ec22009-08-24 16:32:22 -07004299 cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
4300}
4301
Ben Chengba4fc8b2009-06-01 13:00:29 -07004302void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
4303{
4304 /* Used to hold the labels of each block */
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004305 ArmLIR *labelList =
4306 dvmCompilerNew(sizeof(ArmLIR) * cUnit->numBlocks, true);
Bill Buzbee1465db52009-09-23 17:17:35 -07004307 GrowableList chainingListByType[kChainingCellLast];
Ben Chengba4fc8b2009-06-01 13:00:29 -07004308 int i;
4309
4310 /*
Ben Cheng38329f52009-07-07 14:19:20 -07004311 * Initialize various types chaining lists.
Ben Chengba4fc8b2009-06-01 13:00:29 -07004312 */
Bill Buzbee1465db52009-09-23 17:17:35 -07004313 for (i = 0; i < kChainingCellLast; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004314 dvmInitGrowableList(&chainingListByType[i], 2);
4315 }
4316
4317 BasicBlock **blockList = cUnit->blockList;
4318
Bill Buzbee6e963e12009-06-17 16:56:19 -07004319 if (cUnit->executionCount) {
4320 /*
4321 * Reserve 6 bytes at the beginning of the trace
4322 * +----------------------------+
4323 * | execution count (4 bytes) |
4324 * +----------------------------+
4325 * | chain cell offset (2 bytes)|
4326 * +----------------------------+
4327 * ...and then code to increment the execution
4328 * count:
4329 * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
4330 * sub r0, #10 @ back up to addr of executionCount
4331 * ldr r1, [r0]
4332 * add r1, #1
4333 * str r1, [r0]
4334 */
Bill Buzbee1465db52009-09-23 17:17:35 -07004335 newLIR1(cUnit, kArm16BitData, 0);
4336 newLIR1(cUnit, kArm16BitData, 0);
Ben Chengcc6600c2009-06-22 14:45:16 -07004337 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004338 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004339 cUnit->headerSize = 6;
Bill Buzbee270c1d62009-08-13 16:58:07 -07004340 /* Thumb instruction used directly here to ensure correct size */
Bill Buzbee1465db52009-09-23 17:17:35 -07004341 newLIR2(cUnit, kThumbMovRR_H2L, r0, rpc);
4342 newLIR2(cUnit, kThumbSubRI8, r0, 10);
4343 newLIR3(cUnit, kThumbLdrRRI5, r1, r0, 0);
4344 newLIR2(cUnit, kThumbAddRI8, r1, 1);
4345 newLIR3(cUnit, kThumbStrRRI5, r1, r0, 0);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004346 } else {
4347 /* Just reserve 2 bytes for the chain cell offset */
Ben Chengcc6600c2009-06-22 14:45:16 -07004348 cUnit->chainCellOffsetLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004349 (LIR *) newLIR1(cUnit, kArm16BitData, CHAIN_CELL_OFFSET_TAG);
Bill Buzbee6e963e12009-06-17 16:56:19 -07004350 cUnit->headerSize = 2;
4351 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07004352
Ben Chengba4fc8b2009-06-01 13:00:29 -07004353 /* Handle the content in each basic block */
4354 for (i = 0; i < cUnit->numBlocks; i++) {
4355 blockList[i]->visited = true;
4356 MIR *mir;
4357
4358 labelList[i].operands[0] = blockList[i]->startOffset;
4359
Bill Buzbee1465db52009-09-23 17:17:35 -07004360 if (blockList[i]->blockType >= kChainingCellLast) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004361 /*
4362 * Append the label pseudo LIR first. Chaining cells will be handled
4363 * separately afterwards.
4364 */
4365 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
4366 }
4367
Bill Buzbee1465db52009-09-23 17:17:35 -07004368 if (blockList[i]->blockType == kEntryBlock) {
4369 labelList[i].opCode = ARM_PSEUDO_kEntryBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07004370 if (blockList[i]->firstMIRInsn == NULL) {
4371 continue;
4372 } else {
4373 setupLoopEntryBlock(cUnit, blockList[i],
4374 &labelList[blockList[i]->fallThrough->id]);
4375 }
Bill Buzbee1465db52009-09-23 17:17:35 -07004376 } else if (blockList[i]->blockType == kExitBlock) {
4377 labelList[i].opCode = ARM_PSEUDO_kExitBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -07004378 goto gen_fallthrough;
Bill Buzbee1465db52009-09-23 17:17:35 -07004379 } else if (blockList[i]->blockType == kDalvikByteCode) {
4380 labelList[i].opCode = kArmPseudoNormalBlockLabel;
Ben Chenge9695e52009-06-16 16:11:47 -07004381 /* Reset the register state */
Bill Buzbee1465db52009-09-23 17:17:35 -07004382 resetRegPool(cUnit);
4383 clobberAllRegs(cUnit);
4384 resetNullCheckTracker(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004385 } else {
4386 switch (blockList[i]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004387 case kChainingCellNormal:
4388 labelList[i].opCode = ARM_PSEUDO_kChainingCellNormal;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004389 /* handle the codegen later */
4390 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004391 &chainingListByType[kChainingCellNormal], (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004392 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004393 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07004394 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004395 ARM_PSEUDO_kChainingCellInvokeSingleton;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004396 labelList[i].operands[0] =
4397 (int) blockList[i]->containingMethod;
4398 /* handle the codegen later */
4399 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004400 &chainingListByType[kChainingCellInvokeSingleton],
Ben Cheng38329f52009-07-07 14:19:20 -07004401 (void *) i);
4402 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004403 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07004404 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004405 ARM_PSEUDO_kChainingCellInvokePredicted;
Ben Cheng38329f52009-07-07 14:19:20 -07004406 /* handle the codegen later */
4407 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004408 &chainingListByType[kChainingCellInvokePredicted],
Ben Cheng38329f52009-07-07 14:19:20 -07004409 (void *) i);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004410 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004411 case kChainingCellHot:
Ben Chengba4fc8b2009-06-01 13:00:29 -07004412 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004413 ARM_PSEUDO_kChainingCellHot;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004414 /* handle the codegen later */
4415 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004416 &chainingListByType[kChainingCellHot],
Ben Chengba4fc8b2009-06-01 13:00:29 -07004417 (void *) i);
4418 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004419 case kPCReconstruction:
Ben Chengba4fc8b2009-06-01 13:00:29 -07004420 /* Make sure exception handling block is next */
4421 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004422 ARM_PSEUDO_kPCReconstruction_BLOCK_LABEL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004423 assert (i == cUnit->numBlocks - 2);
4424 handlePCReconstruction(cUnit, &labelList[i+1]);
4425 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004426 case kExceptionHandling:
4427 labelList[i].opCode = kArmPseudoEHBlockLabel;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004428 if (cUnit->pcReconstructionList.numUsed) {
Bill Buzbee270c1d62009-08-13 16:58:07 -07004429 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4430 jitToInterpEntries.dvmJitToInterpPunt),
4431 r1);
Bill Buzbee1465db52009-09-23 17:17:35 -07004432 opReg(cUnit, kOpBlx, r1);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004433 }
4434 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004435#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07004436 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07004437 labelList[i].opCode =
Bill Buzbee1465db52009-09-23 17:17:35 -07004438 ARM_PSEUDO_kChainingCellBackwardBranch;
Jeff Hao97319a82009-08-12 16:57:15 -07004439 /* handle the codegen later */
4440 dvmInsertGrowableList(
Bill Buzbee1465db52009-09-23 17:17:35 -07004441 &chainingListByType[kChainingCellBackwardBranch],
Jeff Hao97319a82009-08-12 16:57:15 -07004442 (void *) i);
4443 break;
4444#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004445 default:
4446 break;
4447 }
4448 continue;
4449 }
Ben Chenge9695e52009-06-16 16:11:47 -07004450
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004451 ArmLIR *headLIR = NULL;
Ben Chenge9695e52009-06-16 16:11:47 -07004452
Ben Chengba4fc8b2009-06-01 13:00:29 -07004453 for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004454
4455 resetRegPool(cUnit);
4456 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
4457 clobberAllRegs(cUnit);
4458 }
4459
4460 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
4461 resetDefTracking(cUnit);
4462 }
4463
4464 if (mir->dalvikInsn.opCode >= kMirOpFirst) {
Ben Cheng4238ec22009-08-24 16:32:22 -07004465 handleExtendedMIR(cUnit, mir);
4466 continue;
4467 }
4468
Bill Buzbee1465db52009-09-23 17:17:35 -07004469
Ben Chengba4fc8b2009-06-01 13:00:29 -07004470 OpCode dalvikOpCode = mir->dalvikInsn.opCode;
4471 InstructionFormat dalvikFormat =
4472 dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
Bill Buzbee89efc3d2009-07-28 11:22:22 -07004473 ArmLIR *boundaryLIR =
Bill Buzbee1465db52009-09-23 17:17:35 -07004474 newLIR2(cUnit, ARM_PSEUDO_kDalvikByteCode_BOUNDARY,
Ben Chengccd6c012009-10-15 14:52:45 -07004475 mir->offset,
4476 (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn)
4477 );
Ben Cheng4238ec22009-08-24 16:32:22 -07004478 if (mir->ssaRep) {
4479 char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
Bill Buzbee1465db52009-09-23 17:17:35 -07004480 newLIR1(cUnit, kArmPseudoSSARep, (int) ssaString);
Ben Cheng4238ec22009-08-24 16:32:22 -07004481 }
4482
Ben Chenge9695e52009-06-16 16:11:47 -07004483 /* Remember the first LIR for this block */
4484 if (headLIR == NULL) {
4485 headLIR = boundaryLIR;
Ben Chengd7d426a2009-09-22 11:23:36 -07004486 /* Set the first boundaryLIR as a scheduling barrier */
4487 headLIR->defMask = ENCODE_ALL;
Ben Chenge9695e52009-06-16 16:11:47 -07004488 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004489
Ben Chengba4fc8b2009-06-01 13:00:29 -07004490 bool notHandled;
4491 /*
4492 * Debugging: screen the opcode first to see if it is in the
4493 * do[-not]-compile list
4494 */
4495 bool singleStepMe =
4496 gDvmJit.includeSelectedOp !=
4497 ((gDvmJit.opList[dalvikOpCode >> 3] &
4498 (1 << (dalvikOpCode & 0x7))) !=
4499 0);
Jeff Hao97319a82009-08-12 16:57:15 -07004500#if defined(WITH_SELF_VERIFICATION)
4501 /* Punt on opcodes we can't replay */
4502 if (selfVerificationPuntOps(dalvikOpCode))
4503 singleStepMe = true;
4504#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004505 if (singleStepMe || cUnit->allSingleStep) {
4506 notHandled = false;
4507 genInterpSingleStep(cUnit, mir);
4508 } else {
4509 opcodeCoverage[dalvikOpCode]++;
4510 switch (dalvikFormat) {
4511 case kFmt10t:
4512 case kFmt20t:
4513 case kFmt30t:
4514 notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
4515 mir, blockList[i], labelList);
4516 break;
4517 case kFmt10x:
4518 notHandled = handleFmt10x(cUnit, mir);
4519 break;
4520 case kFmt11n:
4521 case kFmt31i:
4522 notHandled = handleFmt11n_Fmt31i(cUnit, mir);
4523 break;
4524 case kFmt11x:
4525 notHandled = handleFmt11x(cUnit, mir);
4526 break;
4527 case kFmt12x:
4528 notHandled = handleFmt12x(cUnit, mir);
4529 break;
4530 case kFmt20bc:
4531 notHandled = handleFmt20bc(cUnit, mir);
4532 break;
4533 case kFmt21c:
4534 case kFmt31c:
4535 notHandled = handleFmt21c_Fmt31c(cUnit, mir);
4536 break;
4537 case kFmt21h:
4538 notHandled = handleFmt21h(cUnit, mir);
4539 break;
4540 case kFmt21s:
4541 notHandled = handleFmt21s(cUnit, mir);
4542 break;
4543 case kFmt21t:
4544 notHandled = handleFmt21t(cUnit, mir, blockList[i],
4545 labelList);
4546 break;
4547 case kFmt22b:
4548 case kFmt22s:
4549 notHandled = handleFmt22b_Fmt22s(cUnit, mir);
4550 break;
4551 case kFmt22c:
4552 notHandled = handleFmt22c(cUnit, mir);
4553 break;
4554 case kFmt22cs:
4555 notHandled = handleFmt22cs(cUnit, mir);
4556 break;
4557 case kFmt22t:
4558 notHandled = handleFmt22t(cUnit, mir, blockList[i],
4559 labelList);
4560 break;
4561 case kFmt22x:
4562 case kFmt32x:
4563 notHandled = handleFmt22x_Fmt32x(cUnit, mir);
4564 break;
4565 case kFmt23x:
4566 notHandled = handleFmt23x(cUnit, mir);
4567 break;
4568 case kFmt31t:
4569 notHandled = handleFmt31t(cUnit, mir);
4570 break;
4571 case kFmt3rc:
4572 case kFmt35c:
4573 notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
4574 labelList);
4575 break;
4576 case kFmt3rms:
4577 case kFmt35ms:
4578 notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
4579 labelList);
4580 break;
4581 case kFmt3inline:
4582 notHandled = handleFmt3inline(cUnit, mir);
4583 break;
4584 case kFmt51l:
4585 notHandled = handleFmt51l(cUnit, mir);
4586 break;
4587 default:
4588 notHandled = true;
4589 break;
4590 }
4591 }
4592 if (notHandled) {
4593 LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
4594 mir->offset,
4595 dalvikOpCode, getOpcodeName(dalvikOpCode),
4596 dalvikFormat);
4597 dvmAbort();
4598 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004599 }
4600 }
Ben Cheng4238ec22009-08-24 16:32:22 -07004601
Bill Buzbee1465db52009-09-23 17:17:35 -07004602 if (blockList[i]->blockType == kEntryBlock) {
Ben Cheng4238ec22009-08-24 16:32:22 -07004603 dvmCompilerAppendLIR(cUnit,
4604 (LIR *) cUnit->loopAnalysis->branchToBody);
4605 dvmCompilerAppendLIR(cUnit,
4606 (LIR *) cUnit->loopAnalysis->branchToPCR);
4607 }
4608
4609 if (headLIR) {
4610 /*
4611 * Eliminate redundant loads/stores and delay stores into later
4612 * slots
4613 */
4614 dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
4615 cUnit->lastLIRInsn);
4616 }
4617
4618gen_fallthrough:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004619 /*
4620 * Check if the block is terminated due to trace length constraint -
4621 * insert an unconditional branch to the chaining cell.
4622 */
4623 if (blockList[i]->needFallThroughBranch) {
4624 genUnconditionalBranch(cUnit,
4625 &labelList[blockList[i]->fallThrough->id]);
4626 }
4627
Ben Chengba4fc8b2009-06-01 13:00:29 -07004628 }
4629
Ben Chenge9695e52009-06-16 16:11:47 -07004630 /* Handle the chaining cells in predefined order */
Bill Buzbee1465db52009-09-23 17:17:35 -07004631 for (i = 0; i < kChainingCellLast; i++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07004632 size_t j;
4633 int *blockIdList = (int *) chainingListByType[i].elemList;
4634
4635 cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
4636
4637 /* No chaining cells of this type */
4638 if (cUnit->numChainingCells[i] == 0)
4639 continue;
4640
4641 /* Record the first LIR for a new type of chaining cell */
4642 cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
4643
4644 for (j = 0; j < chainingListByType[i].numUsed; j++) {
4645 int blockId = blockIdList[j];
4646
4647 /* Align this chaining cell first */
Bill Buzbee1465db52009-09-23 17:17:35 -07004648 newLIR0(cUnit, kArmPseudoPseudoAlign4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004649
4650 /* Insert the pseudo chaining instruction */
4651 dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
4652
4653
4654 switch (blockList[blockId]->blockType) {
Bill Buzbee1465db52009-09-23 17:17:35 -07004655 case kChainingCellNormal:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004656 handleNormalChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004657 blockList[blockId]->startOffset);
4658 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004659 case kChainingCellInvokeSingleton:
Ben Cheng38329f52009-07-07 14:19:20 -07004660 handleInvokeSingletonChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004661 blockList[blockId]->containingMethod);
4662 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004663 case kChainingCellInvokePredicted:
Ben Cheng38329f52009-07-07 14:19:20 -07004664 handleInvokePredictedChainingCell(cUnit);
4665 break;
Bill Buzbee1465db52009-09-23 17:17:35 -07004666 case kChainingCellHot:
Ben Cheng1efc9c52009-06-08 18:25:27 -07004667 handleHotChainingCell(cUnit,
Ben Chengba4fc8b2009-06-01 13:00:29 -07004668 blockList[blockId]->startOffset);
4669 break;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -07004670#if defined(WITH_SELF_VERIFICATION) || defined(WITH_JIT_TUNING)
Bill Buzbee1465db52009-09-23 17:17:35 -07004671 case kChainingCellBackwardBranch:
Jeff Hao97319a82009-08-12 16:57:15 -07004672 handleBackwardBranchChainingCell(cUnit,
4673 blockList[blockId]->startOffset);
4674 break;
4675#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07004676 default:
Bill Buzbee1465db52009-09-23 17:17:35 -07004677 LOGE("Bad blocktype %d", blockList[blockId]->blockType);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004678 dvmAbort();
4679 break;
4680 }
4681 }
4682 }
Ben Chenge9695e52009-06-16 16:11:47 -07004683
Ben Cheng6c10a972009-10-29 14:39:18 -07004684 /*
4685 * Generate the branch to the dvmJitToInterpNoChain entry point at the end
4686 * of all chaining cells for the overflow cases.
4687 */
4688 if (cUnit->switchOverflowPad) {
4689 loadConstant(cUnit, r0, (int) cUnit->switchOverflowPad);
4690 loadWordDisp(cUnit, rGLUE, offsetof(InterpState,
4691 jitToInterpEntries.dvmJitToInterpNoChain), r2);
4692 opRegReg(cUnit, kOpAdd, r1, r1);
4693 opRegRegReg(cUnit, kOpAdd, r4PC, r0, r1);
4694#if defined(EXIT_STATS)
4695 loadConstant(cUnit, r0, kSwitchOverflow);
4696#endif
4697 opReg(cUnit, kOpBlx, r2);
4698 }
4699
Ben Chenge9695e52009-06-16 16:11:47 -07004700 dvmCompilerApplyGlobalOptimizations(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004701}
4702
4703/* Accept the work and start compiling */
Bill Buzbee716f1202009-07-23 13:22:09 -07004704bool dvmCompilerDoWork(CompilerWorkOrder *work)
Ben Chengba4fc8b2009-06-01 13:00:29 -07004705{
Ben Chengccd6c012009-10-15 14:52:45 -07004706 bool res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004707
Ben Chengccd6c012009-10-15 14:52:45 -07004708 if (gDvmJit.codeCacheFull) {
4709 return false;
4710 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07004711
Ben Chengccd6c012009-10-15 14:52:45 -07004712 switch (work->kind) {
4713 case kWorkOrderMethod:
4714 res = dvmCompileMethod(work->info, &work->result);
4715 break;
4716 case kWorkOrderTrace:
4717 /* Start compilation with maximally allowed trace length */
4718 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
4719 break;
4720 case kWorkOrderTraceDebug: {
4721 bool oldPrintMe = gDvmJit.printMe;
4722 gDvmJit.printMe = true;
4723 /* Start compilation with maximally allowed trace length */
4724 res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
4725 gDvmJit.printMe = oldPrintMe;;
4726 break;
4727 }
4728 default:
4729 res = false;
4730 dvmAbort();
4731 }
4732 return res;
Ben Chengba4fc8b2009-06-01 13:00:29 -07004733}
4734
Ben Chengba4fc8b2009-06-01 13:00:29 -07004735/* Architectural-specific debugging helpers go here */
4736void dvmCompilerArchDump(void)
4737{
4738 /* Print compiled opcode in this VM instance */
4739 int i, start, streak;
4740 char buf[1024];
4741
4742 streak = i = 0;
4743 buf[0] = 0;
4744 while (opcodeCoverage[i] == 0 && i < 256) {
4745 i++;
4746 }
4747 if (i == 256) {
4748 return;
4749 }
4750 for (start = i++, streak = 1; i < 256; i++) {
4751 if (opcodeCoverage[i]) {
4752 streak++;
4753 } else {
4754 if (streak == 1) {
4755 sprintf(buf+strlen(buf), "%x,", start);
4756 } else {
4757 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
4758 }
4759 streak = 0;
4760 while (opcodeCoverage[i] == 0 && i < 256) {
4761 i++;
4762 }
4763 if (i < 256) {
4764 streak = 1;
4765 start = i;
4766 }
4767 }
4768 }
4769 if (streak) {
4770 if (streak == 1) {
4771 sprintf(buf+strlen(buf), "%x", start);
4772 } else {
4773 sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
4774 }
4775 }
4776 if (strlen(buf)) {
Ben Cheng8b258bf2009-06-24 17:27:07 -07004777 LOGD("dalvik.vm.jit.op = %s", buf);
Ben Chengba4fc8b2009-06-01 13:00:29 -07004778 }
4779}
Ben Chengd7d426a2009-09-22 11:23:36 -07004780
4781/* Common initialization routine for an architecture family */
4782bool dvmCompilerArchInit()
4783{
4784 int i;
4785
Bill Buzbee1465db52009-09-23 17:17:35 -07004786 for (i = 0; i < kArmLast; i++) {
Ben Chengd7d426a2009-09-22 11:23:36 -07004787 if (EncodingMap[i].opCode != i) {
4788 LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
4789 EncodingMap[i].name, i, EncodingMap[i].opCode);
4790 dvmAbort();
4791 }
4792 }
4793
4794 return compilerArchVariantInit();
4795}