• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* forward declarations of goto targets */
2 GOTO_TARGET_DECL(filledNewArray, bool methodCallRange);
3 GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange);
4 GOTO_TARGET_DECL(invokeSuper, bool methodCallRange);
5 GOTO_TARGET_DECL(invokeInterface, bool methodCallRange);
6 GOTO_TARGET_DECL(invokeDirect, bool methodCallRange);
7 GOTO_TARGET_DECL(invokeStatic, bool methodCallRange);
8 GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange);
9 GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange);
10 GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
11     u2 count, u2 regs);
12 GOTO_TARGET_DECL(returnFromMethod);
13 GOTO_TARGET_DECL(exceptionThrown);
14 
15 /*
16  * ===========================================================================
17  *
18  * What follows are opcode definitions shared between multiple opcodes with
19  * minor substitutions handled by the C pre-processor.  These should probably
20  * use the mterp substitution mechanism instead, with the code here moved
21  * into common fragment files (like the asm "binop.S"), although it's hard
22  * to give up the C preprocessor in favor of the much simpler text subst.
23  *
24  * ===========================================================================
25  */
26 
27 #define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype)                \
28     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
29         vdst = INST_A(inst);                                                \
30         vsrc1 = INST_B(inst);                                               \
31         ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
32         SET_REGISTER##_totype(vdst,                                         \
33             GET_REGISTER##_fromtype(vsrc1));                                \
34         FINISH(1);
35 
36 #define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype,       \
37         _tovtype, _tortype)                                                 \
38     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
39     {                                                                       \
40         /* spec defines specific handling for +/- inf and NaN values */     \
41         _fromvtype val;                                                     \
42         _tovtype intMin, intMax, result;                                    \
43         vdst = INST_A(inst);                                                \
44         vsrc1 = INST_B(inst);                                               \
45         ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
46         val = GET_REGISTER##_fromrtype(vsrc1);                              \
47         intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1);                 \
48         intMax = ~intMin;                                                   \
49         result = (_tovtype) val;                                            \
50         if (val >= intMax)          /* +inf */                              \
51             result = intMax;                                                \
52         else if (val <= intMin)     /* -inf */                              \
53             result = intMin;                                                \
54         else if (val != val)        /* NaN */                               \
55             result = 0;                                                     \
56         else                                                                \
57             result = (_tovtype) val;                                        \
58         SET_REGISTER##_tortype(vdst, result);                               \
59     }                                                                       \
60     FINISH(1);
61 
62 #define HANDLE_INT_TO_SMALL(_opcode, _opname, _type)                        \
63     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
64         vdst = INST_A(inst);                                                \
65         vsrc1 = INST_B(inst);                                               \
66         ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1);                \
67         SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1));                    \
68         FINISH(1);
69 
70 /* NOTE: the comparison result is always a signed 4-byte integer */
71 #define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal)          \
72     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
73     {                                                                       \
74         int result;                                                         \
75         u2 regs;                                                            \
76         _varType val1, val2;                                                \
77         vdst = INST_AA(inst);                                               \
78         regs = FETCH(1);                                                    \
79         vsrc1 = regs & 0xff;                                                \
80         vsrc2 = regs >> 8;                                                  \
81         ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);         \
82         val1 = GET_REGISTER##_type(vsrc1);                                  \
83         val2 = GET_REGISTER##_type(vsrc2);                                  \
84         if (val1 == val2)                                                   \
85             result = 0;                                                     \
86         else if (val1 < val2)                                               \
87             result = -1;                                                    \
88         else if (val1 > val2)                                               \
89             result = 1;                                                     \
90         else                                                                \
91             result = (_nanVal);                                             \
92         ILOGV("+ result=%d", result);                                       \
93         SET_REGISTER(vdst, result);                                         \
94     }                                                                       \
95     FINISH(2);
96 
97 #define HANDLE_OP_IF_XX(_opcode, _opname, _cmp)                             \
98     HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/)                                \
99         vsrc1 = INST_A(inst);                                               \
100         vsrc2 = INST_B(inst);                                               \
101         if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) {       \
102             int branchOffset = (s2)FETCH(1);    /* sign-extended */         \
103             ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2,        \
104                 branchOffset);                                              \
105             ILOGV("> branch taken");                                        \
106             if (branchOffset < 0)                                           \
107                 PERIODIC_CHECKS(branchOffset);                              \
108             FINISH(branchOffset);                                           \
109         } else {                                                            \
110             ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2);             \
111             FINISH(2);                                                      \
112         }
113 
114 #define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp)                            \
115     HANDLE_OPCODE(_opcode /*vAA, +BBBB*/)                                   \
116         vsrc1 = INST_AA(inst);                                              \
117         if ((s4) GET_REGISTER(vsrc1) _cmp 0) {                              \
118             int branchOffset = (s2)FETCH(1);    /* sign-extended */         \
119             ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset);    \
120             ILOGV("> branch taken");                                        \
121             if (branchOffset < 0)                                           \
122                 PERIODIC_CHECKS(branchOffset);                              \
123             FINISH(branchOffset);                                           \
124         } else {                                                            \
125             ILOGV("|if-%s v%d,-", (_opname), vsrc1);                        \
126             FINISH(2);                                                      \
127         }
128 
129 #define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type)                    \
130     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
131         vdst = INST_A(inst);                                                \
132         vsrc1 = INST_B(inst);                                               \
133         ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
134         SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx);    \
135         FINISH(1);
136 
137 #define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv)                     \
138     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
139     {                                                                       \
140         u2 srcRegs;                                                         \
141         vdst = INST_AA(inst);                                               \
142         srcRegs = FETCH(1);                                                 \
143         vsrc1 = srcRegs & 0xff;                                             \
144         vsrc2 = srcRegs >> 8;                                               \
145         ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1);                   \
146         if (_chkdiv != 0) {                                                 \
147             s4 firstVal, secondVal, result;                                 \
148             firstVal = GET_REGISTER(vsrc1);                                 \
149             secondVal = GET_REGISTER(vsrc2);                                \
150             if (secondVal == 0) {                                           \
151                 EXPORT_PC();                                                \
152                 dvmThrowArithmeticException("divide by zero");              \
153                 GOTO_exceptionThrown();                                     \
154             }                                                               \
155             if ((u4)firstVal == 0x80000000 && secondVal == -1) {            \
156                 if (_chkdiv == 1)                                           \
157                     result = firstVal;  /* division */                      \
158                 else                                                        \
159                     result = 0;         /* remainder */                     \
160             } else {                                                        \
161                 result = firstVal _op secondVal;                            \
162             }                                                               \
163             SET_REGISTER(vdst, result);                                     \
164         } else {                                                            \
165             /* non-div/rem case */                                          \
166             SET_REGISTER(vdst,                                              \
167                 (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2));     \
168         }                                                                   \
169     }                                                                       \
170     FINISH(2);
171 
172 #define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op)                     \
173     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
174     {                                                                       \
175         u2 srcRegs;                                                         \
176         vdst = INST_AA(inst);                                               \
177         srcRegs = FETCH(1);                                                 \
178         vsrc1 = srcRegs & 0xff;                                             \
179         vsrc2 = srcRegs >> 8;                                               \
180         ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1);                   \
181         SET_REGISTER(vdst,                                                  \
182             _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f));    \
183     }                                                                       \
184     FINISH(2);
185 
186 #define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv)               \
187     HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/)                               \
188         vdst = INST_A(inst);                                                \
189         vsrc1 = INST_B(inst);                                               \
190         vsrc2 = FETCH(1);                                                   \
191         ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x",                             \
192             (_opname), vdst, vsrc1, vsrc2);                                 \
193         if (_chkdiv != 0) {                                                 \
194             s4 firstVal, result;                                            \
195             firstVal = GET_REGISTER(vsrc1);                                 \
196             if ((s2) vsrc2 == 0) {                                          \
197                 EXPORT_PC();                                                \
198                 dvmThrowArithmeticException("divide by zero");              \
199                 GOTO_exceptionThrown();                                     \
200             }                                                               \
201             if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) {         \
202                 /* won't generate /lit16 instr for this; check anyway */    \
203                 if (_chkdiv == 1)                                           \
204                     result = firstVal;  /* division */                      \
205                 else                                                        \
206                     result = 0;         /* remainder */                     \
207             } else {                                                        \
208                 result = firstVal _op (s2) vsrc2;                           \
209             }                                                               \
210             SET_REGISTER(vdst, result);                                     \
211         } else {                                                            \
212             /* non-div/rem case */                                          \
213             SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2);         \
214         }                                                                   \
215         FINISH(2);
216 
217 #define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv)                \
218     HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/)                               \
219     {                                                                       \
220         u2 litInfo;                                                         \
221         vdst = INST_AA(inst);                                               \
222         litInfo = FETCH(1);                                                 \
223         vsrc1 = litInfo & 0xff;                                             \
224         vsrc2 = litInfo >> 8;       /* constant */                          \
225         ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x",                              \
226             (_opname), vdst, vsrc1, vsrc2);                                 \
227         if (_chkdiv != 0) {                                                 \
228             s4 firstVal, result;                                            \
229             firstVal = GET_REGISTER(vsrc1);                                 \
230             if ((s1) vsrc2 == 0) {                                          \
231                 EXPORT_PC();                                                \
232                 dvmThrowArithmeticException("divide by zero");              \
233                 GOTO_exceptionThrown();                                     \
234             }                                                               \
235             if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) {         \
236                 if (_chkdiv == 1)                                           \
237                     result = firstVal;  /* division */                      \
238                 else                                                        \
239                     result = 0;         /* remainder */                     \
240             } else {                                                        \
241                 result = firstVal _op ((s1) vsrc2);                         \
242             }                                                               \
243             SET_REGISTER(vdst, result);                                     \
244         } else {                                                            \
245             SET_REGISTER(vdst,                                              \
246                 (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2);                   \
247         }                                                                   \
248     }                                                                       \
249     FINISH(2);
250 
251 #define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op)                \
252     HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/)                               \
253     {                                                                       \
254         u2 litInfo;                                                         \
255         vdst = INST_AA(inst);                                               \
256         litInfo = FETCH(1);                                                 \
257         vsrc1 = litInfo & 0xff;                                             \
258         vsrc2 = litInfo >> 8;       /* constant */                          \
259         ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x",                              \
260             (_opname), vdst, vsrc1, vsrc2);                                 \
261         SET_REGISTER(vdst,                                                  \
262             _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f));                  \
263     }                                                                       \
264     FINISH(2);
265 
266 #define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv)               \
267     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
268         vdst = INST_A(inst);                                                \
269         vsrc1 = INST_B(inst);                                               \
270         ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1);             \
271         if (_chkdiv != 0) {                                                 \
272             s4 firstVal, secondVal, result;                                 \
273             firstVal = GET_REGISTER(vdst);                                  \
274             secondVal = GET_REGISTER(vsrc1);                                \
275             if (secondVal == 0) {                                           \
276                 EXPORT_PC();                                                \
277                 dvmThrowArithmeticException("divide by zero");              \
278                 GOTO_exceptionThrown();                                     \
279             }                                                               \
280             if ((u4)firstVal == 0x80000000 && secondVal == -1) {            \
281                 if (_chkdiv == 1)                                           \
282                     result = firstVal;  /* division */                      \
283                 else                                                        \
284                     result = 0;         /* remainder */                     \
285             } else {                                                        \
286                 result = firstVal _op secondVal;                            \
287             }                                                               \
288             SET_REGISTER(vdst, result);                                     \
289         } else {                                                            \
290             SET_REGISTER(vdst,                                              \
291                 (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1));      \
292         }                                                                   \
293         FINISH(1);
294 
295 #define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op)               \
296     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
297         vdst = INST_A(inst);                                                \
298         vsrc1 = INST_B(inst);                                               \
299         ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1);             \
300         SET_REGISTER(vdst,                                                  \
301             _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f));     \
302         FINISH(1);
303 
304 #define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv)                    \
305     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
306     {                                                                       \
307         u2 srcRegs;                                                         \
308         vdst = INST_AA(inst);                                               \
309         srcRegs = FETCH(1);                                                 \
310         vsrc1 = srcRegs & 0xff;                                             \
311         vsrc2 = srcRegs >> 8;                                               \
312         ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);       \
313         if (_chkdiv != 0) {                                                 \
314             s8 firstVal, secondVal, result;                                 \
315             firstVal = GET_REGISTER_WIDE(vsrc1);                            \
316             secondVal = GET_REGISTER_WIDE(vsrc2);                           \
317             if (secondVal == 0LL) {                                         \
318                 EXPORT_PC();                                                \
319                 dvmThrowArithmeticException("divide by zero");              \
320                 GOTO_exceptionThrown();                                     \
321             }                                                               \
322             if ((u8)firstVal == 0x8000000000000000ULL &&                    \
323                 secondVal == -1LL)                                          \
324             {                                                               \
325                 if (_chkdiv == 1)                                           \
326                     result = firstVal;  /* division */                      \
327                 else                                                        \
328                     result = 0;         /* remainder */                     \
329             } else {                                                        \
330                 result = firstVal _op secondVal;                            \
331             }                                                               \
332             SET_REGISTER_WIDE(vdst, result);                                \
333         } else {                                                            \
334             SET_REGISTER_WIDE(vdst,                                         \
335                 (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \
336         }                                                                   \
337     }                                                                       \
338     FINISH(2);
339 
340 #define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op)                    \
341     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
342     {                                                                       \
343         u2 srcRegs;                                                         \
344         vdst = INST_AA(inst);                                               \
345         srcRegs = FETCH(1);                                                 \
346         vsrc1 = srcRegs & 0xff;                                             \
347         vsrc2 = srcRegs >> 8;                                               \
348         ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);       \
349         SET_REGISTER_WIDE(vdst,                                             \
350             _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \
351     }                                                                       \
352     FINISH(2);
353 
354 #define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv)              \
355     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
356         vdst = INST_A(inst);                                                \
357         vsrc1 = INST_B(inst);                                               \
358         ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1);            \
359         if (_chkdiv != 0) {                                                 \
360             s8 firstVal, secondVal, result;                                 \
361             firstVal = GET_REGISTER_WIDE(vdst);                             \
362             secondVal = GET_REGISTER_WIDE(vsrc1);                           \
363             if (secondVal == 0LL) {                                         \
364                 EXPORT_PC();                                                \
365                 dvmThrowArithmeticException("divide by zero");              \
366                 GOTO_exceptionThrown();                                     \
367             }                                                               \
368             if ((u8)firstVal == 0x8000000000000000ULL &&                    \
369                 secondVal == -1LL)                                          \
370             {                                                               \
371                 if (_chkdiv == 1)                                           \
372                     result = firstVal;  /* division */                      \
373                 else                                                        \
374                     result = 0;         /* remainder */                     \
375             } else {                                                        \
376                 result = firstVal _op secondVal;                            \
377             }                                                               \
378             SET_REGISTER_WIDE(vdst, result);                                \
379         } else {                                                            \
380             SET_REGISTER_WIDE(vdst,                                         \
381                 (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\
382         }                                                                   \
383         FINISH(1);
384 
385 #define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op)              \
386     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
387         vdst = INST_A(inst);                                                \
388         vsrc1 = INST_B(inst);                                               \
389         ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1);            \
390         SET_REGISTER_WIDE(vdst,                                             \
391             _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \
392         FINISH(1);
393 
394 #define HANDLE_OP_X_FLOAT(_opcode, _opname, _op)                            \
395     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
396     {                                                                       \
397         u2 srcRegs;                                                         \
398         vdst = INST_AA(inst);                                               \
399         srcRegs = FETCH(1);                                                 \
400         vsrc1 = srcRegs & 0xff;                                             \
401         vsrc2 = srcRegs >> 8;                                               \
402         ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);      \
403         SET_REGISTER_FLOAT(vdst,                                            \
404             GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2));       \
405     }                                                                       \
406     FINISH(2);
407 
408 #define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op)                           \
409     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
410     {                                                                       \
411         u2 srcRegs;                                                         \
412         vdst = INST_AA(inst);                                               \
413         srcRegs = FETCH(1);                                                 \
414         vsrc1 = srcRegs & 0xff;                                             \
415         vsrc2 = srcRegs >> 8;                                               \
416         ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);     \
417         SET_REGISTER_DOUBLE(vdst,                                           \
418             GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2));     \
419     }                                                                       \
420     FINISH(2);
421 
422 #define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op)                      \
423     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
424         vdst = INST_A(inst);                                                \
425         vsrc1 = INST_B(inst);                                               \
426         ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1);           \
427         SET_REGISTER_FLOAT(vdst,                                            \
428             GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1));        \
429         FINISH(1);
430 
431 #define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op)                     \
432     HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
433         vdst = INST_A(inst);                                                \
434         vsrc1 = INST_B(inst);                                               \
435         ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1);          \
436         SET_REGISTER_DOUBLE(vdst,                                           \
437             GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1));      \
438         FINISH(1);
439 
440 #define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize)                   \
441     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
442     {                                                                       \
443         ArrayObject* arrayObj;                                              \
444         u2 arrayInfo;                                                       \
445         EXPORT_PC();                                                        \
446         vdst = INST_AA(inst);                                               \
447         arrayInfo = FETCH(1);                                               \
448         vsrc1 = arrayInfo & 0xff;    /* array ptr */                        \
449         vsrc2 = arrayInfo >> 8;      /* index */                            \
450         ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);        \
451         arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);                      \
452         if (!checkForNull((Object*) arrayObj))                              \
453             GOTO_exceptionThrown();                                         \
454         if (GET_REGISTER(vsrc2) >= arrayObj->length) {                      \
455             dvmThrowArrayIndexOutOfBoundsException(                         \
456                 arrayObj->length, GET_REGISTER(vsrc2));                     \
457             GOTO_exceptionThrown();                                         \
458         }                                                                   \
459         SET_REGISTER##_regsize(vdst,                                        \
460             ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]);      \
461         ILOGV("+ AGET[%d]=%#x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));   \
462     }                                                                       \
463     FINISH(2);
464 
465 #define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize)                   \
466     HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
467     {                                                                       \
468         ArrayObject* arrayObj;                                              \
469         u2 arrayInfo;                                                       \
470         EXPORT_PC();                                                        \
471         vdst = INST_AA(inst);       /* AA: source value */                  \
472         arrayInfo = FETCH(1);                                               \
473         vsrc1 = arrayInfo & 0xff;   /* BB: array ptr */                     \
474         vsrc2 = arrayInfo >> 8;     /* CC: index */                         \
475         ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);        \
476         arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);                      \
477         if (!checkForNull((Object*) arrayObj))                              \
478             GOTO_exceptionThrown();                                         \
479         if (GET_REGISTER(vsrc2) >= arrayObj->length) {                      \
480             dvmThrowArrayIndexOutOfBoundsException(                         \
481                 arrayObj->length, GET_REGISTER(vsrc2));                     \
482             GOTO_exceptionThrown();                                         \
483         }                                                                   \
484         ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
485         ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)] =          \
486             GET_REGISTER##_regsize(vdst);                                   \
487     }                                                                       \
488     FINISH(2);
489 
490 /*
491  * It's possible to get a bad value out of a field with sub-32-bit stores
492  * because the -quick versions always operate on 32 bits.  Consider:
493  *   short foo = -1  (sets a 32-bit register to 0xffffffff)
494  *   iput-quick foo  (writes all 32 bits to the field)
495  *   short bar = 1   (sets a 32-bit register to 0x00000001)
496  *   iput-short      (writes the low 16 bits to the field)
497  *   iget-quick foo  (reads all 32 bits from the field, yielding 0xffff0001)
498  * This can only happen when optimized and non-optimized code has interleaved
499  * access to the same field.  This is unlikely but possible.
500  *
501  * The easiest way to fix this is to always read/write 32 bits at a time.  On
502  * a device with a 16-bit data bus this is sub-optimal.  (The alternative
503  * approach is to have sub-int versions of iget-quick, but now we're wasting
504  * Dalvik instruction space and making it less likely that handler code will
505  * already be in the CPU i-cache.)
506  */
507 #define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize)                   \
508     HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
509     {                                                                       \
510         InstField* ifield;                                                  \
511         Object* obj;                                                        \
512         EXPORT_PC();                                                        \
513         vdst = INST_A(inst);                                                \
514         vsrc1 = INST_B(inst);   /* object ptr */                            \
515         ref = FETCH(1);         /* field ref */                             \
516         ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
517         obj = (Object*) GET_REGISTER(vsrc1);                                \
518         if (!checkForNull(obj))                                             \
519             GOTO_exceptionThrown();                                         \
520         ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
521         if (ifield == NULL) {                                               \
522             ifield = dvmResolveInstField(curMethod->clazz, ref);            \
523             if (ifield == NULL)                                             \
524                 GOTO_exceptionThrown();                                     \
525         }                                                                   \
526         SET_REGISTER##_regsize(vdst,                                        \
527             dvmGetField##_ftype(obj, ifield->byteOffset));                  \
528         ILOGV("+ IGET '%s'=0x%08llx", ifield->name,                         \
529             (u8) GET_REGISTER##_regsize(vdst));                             \
530     }                                                                       \
531     FINISH(2);
532 
533 #define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize)             \
534     HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
535     {                                                                       \
536         Object* obj;                                                        \
537         vdst = INST_A(inst);                                                \
538         vsrc1 = INST_B(inst);   /* object ptr */                            \
539         ref = FETCH(1);         /* field offset */                          \
540         ILOGV("|iget%s-quick v%d,v%d,field@+%u",                            \
541             (_opname), vdst, vsrc1, ref);                                   \
542         obj = (Object*) GET_REGISTER(vsrc1);                                \
543         if (!checkForNullExportPC(obj, fp, pc))                             \
544             GOTO_exceptionThrown();                                         \
545         SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref));        \
546         ILOGV("+ IGETQ %d=0x%08llx", ref,                                   \
547             (u8) GET_REGISTER##_regsize(vdst));                             \
548     }                                                                       \
549     FINISH(2);
550 
551 #define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize)                   \
552     HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
553     {                                                                       \
554         InstField* ifield;                                                  \
555         Object* obj;                                                        \
556         EXPORT_PC();                                                        \
557         vdst = INST_A(inst);                                                \
558         vsrc1 = INST_B(inst);   /* object ptr */                            \
559         ref = FETCH(1);         /* field ref */                             \
560         ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
561         obj = (Object*) GET_REGISTER(vsrc1);                                \
562         if (!checkForNull(obj))                                             \
563             GOTO_exceptionThrown();                                         \
564         ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
565         if (ifield == NULL) {                                               \
566             ifield = dvmResolveInstField(curMethod->clazz, ref);            \
567             if (ifield == NULL)                                             \
568                 GOTO_exceptionThrown();                                     \
569         }                                                                   \
570         dvmSetField##_ftype(obj, ifield->byteOffset,                        \
571             GET_REGISTER##_regsize(vdst));                                  \
572         ILOGV("+ IPUT '%s'=0x%08llx", ifield->name,                         \
573             (u8) GET_REGISTER##_regsize(vdst));                             \
574     }                                                                       \
575     FINISH(2);
576 
577 #define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize)             \
578     HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
579     {                                                                       \
580         Object* obj;                                                        \
581         vdst = INST_A(inst);                                                \
582         vsrc1 = INST_B(inst);   /* object ptr */                            \
583         ref = FETCH(1);         /* field offset */                          \
584         ILOGV("|iput%s-quick v%d,v%d,field@0x%04x",                         \
585             (_opname), vdst, vsrc1, ref);                                   \
586         obj = (Object*) GET_REGISTER(vsrc1);                                \
587         if (!checkForNullExportPC(obj, fp, pc))                             \
588             GOTO_exceptionThrown();                                         \
589         dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst));        \
590         ILOGV("+ IPUTQ %d=0x%08llx", ref,                                   \
591             (u8) GET_REGISTER##_regsize(vdst));                             \
592     }                                                                       \
593     FINISH(2);
594 
595 /*
596  * The JIT needs dvmDexGetResolvedField() to return non-null.
597  * Because the portable interpreter is not involved with the JIT
598  * and trace building, we only need the extra check here when this
599  * code is massaged into a stub called from an assembly interpreter.
600  * This is controlled by the JIT_STUB_HACK maco.
601  */
602 
603 #define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize)                   \
604     HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/)                              \
605     {                                                                       \
606         StaticField* sfield;                                                \
607         vdst = INST_AA(inst);                                               \
608         ref = FETCH(1);         /* field ref */                             \
609         ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref);           \
610         sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
611         if (sfield == NULL) {                                               \
612             EXPORT_PC();                                                    \
613             sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
614             if (sfield == NULL)                                             \
615                 GOTO_exceptionThrown();                                     \
616             if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
617                 JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
618             }                                                               \
619         }                                                                   \
620         SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
621         ILOGV("+ SGET '%s'=0x%08llx",                                       \
622             sfield->name, (u8)GET_REGISTER##_regsize(vdst));                \
623     }                                                                       \
624     FINISH(2);
625 
626 #define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize)                   \
627     HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/)                              \
628     {                                                                       \
629         StaticField* sfield;                                                \
630         vdst = INST_AA(inst);                                               \
631         ref = FETCH(1);         /* field ref */                             \
632         ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref);           \
633         sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
634         if (sfield == NULL) {                                               \
635             EXPORT_PC();                                                    \
636             sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
637             if (sfield == NULL)                                             \
638                 GOTO_exceptionThrown();                                     \
639             if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
640                 JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
641             }                                                               \
642         }                                                                   \
643         dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
644         ILOGV("+ SPUT '%s'=0x%08llx",                                       \
645             sfield->name, (u8)GET_REGISTER##_regsize(vdst));                \
646     }                                                                       \
647     FINISH(2);
648