opcommon.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
1/* forward declarations of goto targets */
2GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
3GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
4GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
5GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
6GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
7GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
8GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
9GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
10GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
11    u2 count, u2 regs);
12GOTO_TARGET_DECL(returnFromMethod);
13GOTO_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]=0x%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->field.name,                   \
529            (u8) GET_REGISTER##_regsize(vdst));                             \
530    }                                                                       \
531    FINISH(2);
532
533#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
534    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
535    {                                                                       \
536        InstField* ifield;                                                  \
537        Object* obj;                                                        \
538        EXPORT_PC();                                                        \
539        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
540        vdst = FETCH(3);                                                    \
541        vsrc1 = FETCH(4);                      /* object ptr */             \
542        ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x",                         \
543            (_opname), vdst, vsrc1, ref);                                   \
544        obj = (Object*) GET_REGISTER(vsrc1);                                \
545        if (!checkForNull(obj))                                             \
546            GOTO_exceptionThrown();                                         \
547        ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
548        if (ifield == NULL) {                                               \
549            ifield = dvmResolveInstField(curMethod->clazz, ref);            \
550            if (ifield == NULL)                                             \
551                GOTO_exceptionThrown();                                     \
552        }                                                                   \
553        SET_REGISTER##_regsize(vdst,                                        \
554            dvmGetField##_ftype(obj, ifield->byteOffset));                  \
555        ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name,                   \
556            (u8) GET_REGISTER##_regsize(vdst));                             \
557    }                                                                       \
558    FINISH(5);
559
560#define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize)             \
561    HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
562    {                                                                       \
563        Object* obj;                                                        \
564        vdst = INST_A(inst);                                                \
565        vsrc1 = INST_B(inst);   /* object ptr */                            \
566        ref = FETCH(1);         /* field offset */                          \
567        ILOGV("|iget%s-quick v%d,v%d,field@+%u",                            \
568            (_opname), vdst, vsrc1, ref);                                   \
569        obj = (Object*) GET_REGISTER(vsrc1);                                \
570        if (!checkForNullExportPC(obj, fp, pc))                             \
571            GOTO_exceptionThrown();                                         \
572        SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref));        \
573        ILOGV("+ IGETQ %d=0x%08llx", ref,                                   \
574            (u8) GET_REGISTER##_regsize(vdst));                             \
575    }                                                                       \
576    FINISH(2);
577
578#define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize)                   \
579    HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
580    {                                                                       \
581        InstField* ifield;                                                  \
582        Object* obj;                                                        \
583        EXPORT_PC();                                                        \
584        vdst = INST_A(inst);                                                \
585        vsrc1 = INST_B(inst);   /* object ptr */                            \
586        ref = FETCH(1);         /* field ref */                             \
587        ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
588        obj = (Object*) GET_REGISTER(vsrc1);                                \
589        if (!checkForNull(obj))                                             \
590            GOTO_exceptionThrown();                                         \
591        ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
592        if (ifield == NULL) {                                               \
593            ifield = dvmResolveInstField(curMethod->clazz, ref);            \
594            if (ifield == NULL)                                             \
595                GOTO_exceptionThrown();                                     \
596        }                                                                   \
597        dvmSetField##_ftype(obj, ifield->byteOffset,                        \
598            GET_REGISTER##_regsize(vdst));                                  \
599        ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name,                   \
600            (u8) GET_REGISTER##_regsize(vdst));                             \
601    }                                                                       \
602    FINISH(2);
603
604#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
605    HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/)                 \
606    {                                                                       \
607        InstField* ifield;                                                  \
608        Object* obj;                                                        \
609        EXPORT_PC();                                                        \
610        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
611        vdst = FETCH(3);                                                    \
612        vsrc1 = FETCH(4);                      /* object ptr */             \
613        ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x",                         \
614            (_opname), vdst, vsrc1, ref);                                   \
615        obj = (Object*) GET_REGISTER(vsrc1);                                \
616        if (!checkForNull(obj))                                             \
617            GOTO_exceptionThrown();                                         \
618        ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
619        if (ifield == NULL) {                                               \
620            ifield = dvmResolveInstField(curMethod->clazz, ref);            \
621            if (ifield == NULL)                                             \
622                GOTO_exceptionThrown();                                     \
623        }                                                                   \
624        dvmSetField##_ftype(obj, ifield->byteOffset,                        \
625            GET_REGISTER##_regsize(vdst));                                  \
626        ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name,                   \
627            (u8) GET_REGISTER##_regsize(vdst));                             \
628    }                                                                       \
629    FINISH(5);
630
631#define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize)             \
632    HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
633    {                                                                       \
634        Object* obj;                                                        \
635        vdst = INST_A(inst);                                                \
636        vsrc1 = INST_B(inst);   /* object ptr */                            \
637        ref = FETCH(1);         /* field offset */                          \
638        ILOGV("|iput%s-quick v%d,v%d,field@0x%04x",                         \
639            (_opname), vdst, vsrc1, ref);                                   \
640        obj = (Object*) GET_REGISTER(vsrc1);                                \
641        if (!checkForNullExportPC(obj, fp, pc))                             \
642            GOTO_exceptionThrown();                                         \
643        dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst));        \
644        ILOGV("+ IPUTQ %d=0x%08llx", ref,                                   \
645            (u8) GET_REGISTER##_regsize(vdst));                             \
646    }                                                                       \
647    FINISH(2);
648
649/*
650 * The JIT needs dvmDexGetResolvedField() to return non-null.
651 * Because the portable interpreter is not involved with the JIT
652 * and trace building, we only need the extra check here when this
653 * code is massaged into a stub called from an assembly interpreter.
654 * This is controlled by the JIT_STUB_HACK maco.
655 */
656
657#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize)                   \
658    HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/)                              \
659    {                                                                       \
660        StaticField* sfield;                                                \
661        vdst = INST_AA(inst);                                               \
662        ref = FETCH(1);         /* field ref */                             \
663        ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref);           \
664        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
665        if (sfield == NULL) {                                               \
666            EXPORT_PC();                                                    \
667            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
668            if (sfield == NULL)                                             \
669                GOTO_exceptionThrown();                                     \
670            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
671                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
672            }                                                               \
673        }                                                                   \
674        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
675        ILOGV("+ SGET '%s'=0x%08llx",                                       \
676            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
677    }                                                                       \
678    FINISH(2);
679
680#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
681    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
682    {                                                                       \
683        StaticField* sfield;                                                \
684        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
685        vdst = FETCH(3);                                                    \
686        ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
687        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
688        if (sfield == NULL) {                                               \
689            EXPORT_PC();                                                    \
690            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
691            if (sfield == NULL)                                             \
692                GOTO_exceptionThrown();                                     \
693            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
694                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
695            }                                                               \
696        }                                                                   \
697        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
698        ILOGV("+ SGET '%s'=0x%08llx",                                       \
699            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
700    }                                                                       \
701    FINISH(4);
702
703#define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize)                   \
704    HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/)                              \
705    {                                                                       \
706        StaticField* sfield;                                                \
707        vdst = INST_AA(inst);                                               \
708        ref = FETCH(1);         /* field ref */                             \
709        ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref);           \
710        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
711        if (sfield == NULL) {                                               \
712            EXPORT_PC();                                                    \
713            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
714            if (sfield == NULL)                                             \
715                GOTO_exceptionThrown();                                     \
716            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
717                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
718            }                                                               \
719        }                                                                   \
720        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
721        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
722            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
723    }                                                                       \
724    FINISH(2);
725
726#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize)             \
727    HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/)                        \
728    {                                                                       \
729        StaticField* sfield;                                                \
730        ref = FETCH(1) | (u4)FETCH(2) << 16;   /* field ref */              \
731        vdst = FETCH(3);                                                    \
732        ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref);     \
733        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
734        if (sfield == NULL) {                                               \
735            EXPORT_PC();                                                    \
736            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
737            if (sfield == NULL)                                             \
738                GOTO_exceptionThrown();                                     \
739            if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) {      \
740                JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc));               \
741            }                                                               \
742        }                                                                   \
743        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
744        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
745            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
746    }                                                                       \
747    FINISH(4);
748