blob: 7ee07b32b4315dd6ebce58c5a81ff9e201a9ece4 [file] [log] [blame]
/* forward declarations of goto targets */
GOTO_TARGET_DECL(filledNewArray, bool methodCallRange, bool jumboFormat);
GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange, bool jumboFormat);
GOTO_TARGET_DECL(invokeSuper, bool methodCallRange, bool jumboFormat);
GOTO_TARGET_DECL(invokeInterface, bool methodCallRange, bool jumboFormat);
GOTO_TARGET_DECL(invokeDirect, bool methodCallRange, bool jumboFormat);
GOTO_TARGET_DECL(invokeStatic, bool methodCallRange, bool jumboFormat);
GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange, bool jumboFormat);
GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange, bool jumboFormat);
GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
u2 count, u2 regs);
GOTO_TARGET_DECL(returnFromMethod);
GOTO_TARGET_DECL(exceptionThrown);
/*
* ===========================================================================
*
* What follows are opcode definitions shared between multiple opcodes with
* minor substitutions handled by the C pre-processor. These should probably
* use the mterp substitution mechanism instead, with the code here moved
* into common fragment files (like the asm "binop.S"), although it's hard
* to give up the C preprocessor in favor of the much simpler text subst.
*
* ===========================================================================
*/
#define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
SET_REGISTER##_totype(vdst, \
GET_REGISTER##_fromtype(vsrc1)); \
FINISH(1);
#define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype, \
_tovtype, _tortype) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
{ \
/* spec defines specific handling for +/- inf and NaN values */ \
_fromvtype val; \
_tovtype intMin, intMax, result; \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
val = GET_REGISTER##_fromrtype(vsrc1); \
intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1); \
intMax = ~intMin; \
result = (_tovtype) val; \
if (val >= intMax) /* +inf */ \
result = intMax; \
else if (val <= intMin) /* -inf */ \
result = intMin; \
else if (val != val) /* NaN */ \
result = 0; \
else \
result = (_tovtype) val; \
SET_REGISTER##_tortype(vdst, result); \
} \
FINISH(1);
#define HANDLE_INT_TO_SMALL(_opcode, _opname, _type) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1); \
SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1)); \
FINISH(1);
/* NOTE: the comparison result is always a signed 4-byte integer */
#define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
int result; \
u2 regs; \
_varType val1, val2; \
vdst = INST_AA(inst); \
regs = FETCH(1); \
vsrc1 = regs & 0xff; \
vsrc2 = regs >> 8; \
ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
val1 = GET_REGISTER##_type(vsrc1); \
val2 = GET_REGISTER##_type(vsrc2); \
if (val1 == val2) \
result = 0; \
else if (val1 < val2) \
result = -1; \
else if (val1 > val2) \
result = 1; \
else \
result = (_nanVal); \
ILOGV("+ result=%d\n", result); \
SET_REGISTER(vdst, result); \
} \
FINISH(2);
#define HANDLE_OP_IF_XX(_opcode, _opname, _cmp) \
HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/) \
vsrc1 = INST_A(inst); \
vsrc2 = INST_B(inst); \
if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) { \
int branchOffset = (s2)FETCH(1); /* sign-extended */ \
ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2, \
branchOffset); \
ILOGV("> branch taken"); \
if (branchOffset < 0) \
PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \
FINISH(branchOffset); \
} else { \
ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2); \
FINISH(2); \
}
#define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp) \
HANDLE_OPCODE(_opcode /*vAA, +BBBB*/) \
vsrc1 = INST_AA(inst); \
if ((s4) GET_REGISTER(vsrc1) _cmp 0) { \
int branchOffset = (s2)FETCH(1); /* sign-extended */ \
ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset); \
ILOGV("> branch taken"); \
if (branchOffset < 0) \
PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \
FINISH(branchOffset); \
} else { \
ILOGV("|if-%s v%d,-", (_opname), vsrc1); \
FINISH(2); \
}
#define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx); \
FINISH(1);
#define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
u2 srcRegs; \
vdst = INST_AA(inst); \
srcRegs = FETCH(1); \
vsrc1 = srcRegs & 0xff; \
vsrc2 = srcRegs >> 8; \
ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
if (_chkdiv != 0) { \
s4 firstVal, secondVal, result; \
firstVal = GET_REGISTER(vsrc1); \
secondVal = GET_REGISTER(vsrc2); \
if (secondVal == 0) { \
EXPORT_PC(); \
dvmThrowArithmeticException("divide by zero"); \
GOTO_exceptionThrown(); \
} \
if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
if (_chkdiv == 1) \
result = firstVal; /* division */ \
else \
result = 0; /* remainder */ \
} else { \
result = firstVal _op secondVal; \
} \
SET_REGISTER(vdst, result); \
} else { \
/* non-div/rem case */ \
SET_REGISTER(vdst, \
(s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2)); \
} \
} \
FINISH(2);
#define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
u2 srcRegs; \
vdst = INST_AA(inst); \
srcRegs = FETCH(1); \
vsrc1 = srcRegs & 0xff; \
vsrc2 = srcRegs >> 8; \
ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
SET_REGISTER(vdst, \
_cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f)); \
} \
FINISH(2);
#define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv) \
HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
vsrc2 = FETCH(1); \
ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x", \
(_opname), vdst, vsrc1, vsrc2); \
if (_chkdiv != 0) { \
s4 firstVal, result; \
firstVal = GET_REGISTER(vsrc1); \
if ((s2) vsrc2 == 0) { \
EXPORT_PC(); \
dvmThrowArithmeticException("divide by zero"); \
GOTO_exceptionThrown(); \
} \
if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) { \
/* won't generate /lit16 instr for this; check anyway */ \
if (_chkdiv == 1) \
result = firstVal; /* division */ \
else \
result = 0; /* remainder */ \
} else { \
result = firstVal _op (s2) vsrc2; \
} \
SET_REGISTER(vdst, result); \
} else { \
/* non-div/rem case */ \
SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2); \
} \
FINISH(2);
#define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv) \
HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
{ \
u2 litInfo; \
vdst = INST_AA(inst); \
litInfo = FETCH(1); \
vsrc1 = litInfo & 0xff; \
vsrc2 = litInfo >> 8; /* constant */ \
ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
(_opname), vdst, vsrc1, vsrc2); \
if (_chkdiv != 0) { \
s4 firstVal, result; \
firstVal = GET_REGISTER(vsrc1); \
if ((s1) vsrc2 == 0) { \
EXPORT_PC(); \
dvmThrowArithmeticException("divide by zero"); \
GOTO_exceptionThrown(); \
} \
if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) { \
if (_chkdiv == 1) \
result = firstVal; /* division */ \
else \
result = 0; /* remainder */ \
} else { \
result = firstVal _op ((s1) vsrc2); \
} \
SET_REGISTER(vdst, result); \
} else { \
SET_REGISTER(vdst, \
(s4) GET_REGISTER(vsrc1) _op (s1) vsrc2); \
} \
} \
FINISH(2);
#define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op) \
HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
{ \
u2 litInfo; \
vdst = INST_AA(inst); \
litInfo = FETCH(1); \
vsrc1 = litInfo & 0xff; \
vsrc2 = litInfo >> 8; /* constant */ \
ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
(_opname), vdst, vsrc1, vsrc2); \
SET_REGISTER(vdst, \
_cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f)); \
} \
FINISH(2);
#define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
if (_chkdiv != 0) { \
s4 firstVal, secondVal, result; \
firstVal = GET_REGISTER(vdst); \
secondVal = GET_REGISTER(vsrc1); \
if (secondVal == 0) { \
EXPORT_PC(); \
dvmThrowArithmeticException("divide by zero"); \
GOTO_exceptionThrown(); \
} \
if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
if (_chkdiv == 1) \
result = firstVal; /* division */ \
else \
result = 0; /* remainder */ \
} else { \
result = firstVal _op secondVal; \
} \
SET_REGISTER(vdst, result); \
} else { \
SET_REGISTER(vdst, \
(s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1)); \
} \
FINISH(1);
#define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
SET_REGISTER(vdst, \
_cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f)); \
FINISH(1);
#define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
u2 srcRegs; \
vdst = INST_AA(inst); \
srcRegs = FETCH(1); \
vsrc1 = srcRegs & 0xff; \
vsrc2 = srcRegs >> 8; \
ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
if (_chkdiv != 0) { \
s8 firstVal, secondVal, result; \
firstVal = GET_REGISTER_WIDE(vsrc1); \
secondVal = GET_REGISTER_WIDE(vsrc2); \
if (secondVal == 0LL) { \
EXPORT_PC(); \
dvmThrowArithmeticException("divide by zero"); \
GOTO_exceptionThrown(); \
} \
if ((u8)firstVal == 0x8000000000000000ULL && \
secondVal == -1LL) \
{ \
if (_chkdiv == 1) \
result = firstVal; /* division */ \
else \
result = 0; /* remainder */ \
} else { \
result = firstVal _op secondVal; \
} \
SET_REGISTER_WIDE(vdst, result); \
} else { \
SET_REGISTER_WIDE(vdst, \
(s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \
} \
} \
FINISH(2);
#define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
u2 srcRegs; \
vdst = INST_AA(inst); \
srcRegs = FETCH(1); \
vsrc1 = srcRegs & 0xff; \
vsrc2 = srcRegs >> 8; \
ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
SET_REGISTER_WIDE(vdst, \
_cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \
} \
FINISH(2);
#define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
if (_chkdiv != 0) { \
s8 firstVal, secondVal, result; \
firstVal = GET_REGISTER_WIDE(vdst); \
secondVal = GET_REGISTER_WIDE(vsrc1); \
if (secondVal == 0LL) { \
EXPORT_PC(); \
dvmThrowArithmeticException("divide by zero"); \
GOTO_exceptionThrown(); \
} \
if ((u8)firstVal == 0x8000000000000000ULL && \
secondVal == -1LL) \
{ \
if (_chkdiv == 1) \
result = firstVal; /* division */ \
else \
result = 0; /* remainder */ \
} else { \
result = firstVal _op secondVal; \
} \
SET_REGISTER_WIDE(vdst, result); \
} else { \
SET_REGISTER_WIDE(vdst, \
(s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\
} \
FINISH(1);
#define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
SET_REGISTER_WIDE(vdst, \
_cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \
FINISH(1);
#define HANDLE_OP_X_FLOAT(_opcode, _opname, _op) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
u2 srcRegs; \
vdst = INST_AA(inst); \
srcRegs = FETCH(1); \
vsrc1 = srcRegs & 0xff; \
vsrc2 = srcRegs >> 8; \
ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
SET_REGISTER_FLOAT(vdst, \
GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2)); \
} \
FINISH(2);
#define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
u2 srcRegs; \
vdst = INST_AA(inst); \
srcRegs = FETCH(1); \
vsrc1 = srcRegs & 0xff; \
vsrc2 = srcRegs >> 8; \
ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
SET_REGISTER_DOUBLE(vdst, \
GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2)); \
} \
FINISH(2);
#define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1); \
SET_REGISTER_FLOAT(vdst, \
GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1)); \
FINISH(1);
#define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op) \
HANDLE_OPCODE(_opcode /*vA, vB*/) \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); \
ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1); \
SET_REGISTER_DOUBLE(vdst, \
GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1)); \
FINISH(1);
#define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
ArrayObject* arrayObj; \
u2 arrayInfo; \
EXPORT_PC(); \
vdst = INST_AA(inst); \
arrayInfo = FETCH(1); \
vsrc1 = arrayInfo & 0xff; /* array ptr */ \
vsrc2 = arrayInfo >> 8; /* index */ \
ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
if (!checkForNull((Object*) arrayObj)) \
GOTO_exceptionThrown(); \
if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
dvmThrowArrayIndexOutOfBoundsException( \
GET_REGISTER(vsrc2), arrayObj->length); \
GOTO_exceptionThrown(); \
} \
SET_REGISTER##_regsize(vdst, \
((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)]); \
ILOGV("+ AGET[%d]=0x%x", GET_REGISTER(vsrc2), GET_REGISTER(vdst)); \
} \
FINISH(2);
#define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
{ \
ArrayObject* arrayObj; \
u2 arrayInfo; \
EXPORT_PC(); \
vdst = INST_AA(inst); /* AA: source value */ \
arrayInfo = FETCH(1); \
vsrc1 = arrayInfo & 0xff; /* BB: array ptr */ \
vsrc2 = arrayInfo >> 8; /* CC: index */ \
ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
if (!checkForNull((Object*) arrayObj)) \
GOTO_exceptionThrown(); \
if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
dvmThrowArrayIndexOutOfBoundsException( \
GET_REGISTER(vsrc2), arrayObj->length); \
GOTO_exceptionThrown(); \
} \
ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)] = \
GET_REGISTER##_regsize(vdst); \
} \
FINISH(2);
/*
* It's possible to get a bad value out of a field with sub-32-bit stores
* because the -quick versions always operate on 32 bits. Consider:
* short foo = -1 (sets a 32-bit register to 0xffffffff)
* iput-quick foo (writes all 32 bits to the field)
* short bar = 1 (sets a 32-bit register to 0x00000001)
* iput-short (writes the low 16 bits to the field)
* iget-quick foo (reads all 32 bits from the field, yielding 0xffff0001)
* This can only happen when optimized and non-optimized code has interleaved
* access to the same field. This is unlikely but possible.
*
* The easiest way to fix this is to always read/write 32 bits at a time. On
* a device with a 16-bit data bus this is sub-optimal. (The alternative
* approach is to have sub-int versions of iget-quick, but now we're wasting
* Dalvik instruction space and making it less likely that handler code will
* already be in the CPU i-cache.)
*/
#define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
{ \
InstField* ifield; \
Object* obj; \
EXPORT_PC(); \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); /* object ptr */ \
ref = FETCH(1); /* field ref */ \
ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
obj = (Object*) GET_REGISTER(vsrc1); \
if (!checkForNull(obj)) \
GOTO_exceptionThrown(); \
ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
if (ifield == NULL) { \
ifield = dvmResolveInstField(curMethod->clazz, ref); \
if (ifield == NULL) \
GOTO_exceptionThrown(); \
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
(u8) GET_REGISTER##_regsize(vdst)); \
UPDATE_FIELD_GET(&ifield->field); \
} \
FINISH(2);
#define HANDLE_IGET_X_JUMBO(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/) \
{ \
InstField* ifield; \
Object* obj; \
EXPORT_PC(); \
ref = FETCH(1) | (u4)FETCH(2) << 16; /* field ref */ \
vdst = FETCH(3); \
vsrc1 = FETCH(4); /* object ptr */ \
ILOGV("|iget%s/jumbo v%d,v%d,field@0x%08x", \
(_opname), vdst, vsrc1, ref); \
obj = (Object*) GET_REGISTER(vsrc1); \
if (!checkForNull(obj)) \
GOTO_exceptionThrown(); \
ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
if (ifield == NULL) { \
ifield = dvmResolveInstField(curMethod->clazz, ref); \
if (ifield == NULL) \
GOTO_exceptionThrown(); \
} \
SET_REGISTER##_regsize(vdst, \
dvmGetField##_ftype(obj, ifield->byteOffset)); \
ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
(u8) GET_REGISTER##_regsize(vdst)); \
UPDATE_FIELD_GET(&ifield->field); \
} \
FINISH(5);
#define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
{ \
Object* obj; \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); /* object ptr */ \
ref = FETCH(1); /* field offset */ \
ILOGV("|iget%s-quick v%d,v%d,field@+%u", \
(_opname), vdst, vsrc1, ref); \
obj = (Object*) GET_REGISTER(vsrc1); \
if (!checkForNullExportPC(obj, fp, pc)) \
GOTO_exceptionThrown(); \
SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref)); \
ILOGV("+ IGETQ %d=0x%08llx", ref, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
#define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
{ \
InstField* ifield; \
Object* obj; \
EXPORT_PC(); \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); /* object ptr */ \
ref = FETCH(1); /* field ref */ \
ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
obj = (Object*) GET_REGISTER(vsrc1); \
if (!checkForNull(obj)) \
GOTO_exceptionThrown(); \
ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
if (ifield == NULL) { \
ifield = dvmResolveInstField(curMethod->clazz, ref); \
if (ifield == NULL) \
GOTO_exceptionThrown(); \
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
(u8) GET_REGISTER##_regsize(vdst)); \
UPDATE_FIELD_PUT(&ifield->field); \
} \
FINISH(2);
#define HANDLE_IPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vBBBB, vCCCC, class@AAAAAAAA*/) \
{ \
InstField* ifield; \
Object* obj; \
EXPORT_PC(); \
ref = FETCH(1) | (u4)FETCH(2) << 16; /* field ref */ \
vdst = FETCH(3); \
vsrc1 = FETCH(4); /* object ptr */ \
ILOGV("|iput%s/jumbo v%d,v%d,field@0x%08x", \
(_opname), vdst, vsrc1, ref); \
obj = (Object*) GET_REGISTER(vsrc1); \
if (!checkForNull(obj)) \
GOTO_exceptionThrown(); \
ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
if (ifield == NULL) { \
ifield = dvmResolveInstField(curMethod->clazz, ref); \
if (ifield == NULL) \
GOTO_exceptionThrown(); \
} \
dvmSetField##_ftype(obj, ifield->byteOffset, \
GET_REGISTER##_regsize(vdst)); \
ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
(u8) GET_REGISTER##_regsize(vdst)); \
UPDATE_FIELD_PUT(&ifield->field); \
} \
FINISH(5);
#define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
{ \
Object* obj; \
vdst = INST_A(inst); \
vsrc1 = INST_B(inst); /* object ptr */ \
ref = FETCH(1); /* field offset */ \
ILOGV("|iput%s-quick v%d,v%d,field@0x%04x", \
(_opname), vdst, vsrc1, ref); \
obj = (Object*) GET_REGISTER(vsrc1); \
if (!checkForNullExportPC(obj, fp, pc)) \
GOTO_exceptionThrown(); \
dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ IPUTQ %d=0x%08llx", ref, \
(u8) GET_REGISTER##_regsize(vdst)); \
} \
FINISH(2);
/*
* The JIT needs dvmDexGetResolvedField() to return non-null.
* Since we use the portable interpreter to build the trace, the extra
* checks in HANDLE_SGET_X and HANDLE_SPUT_X are not needed for mterp.
*/
#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
StaticField* sfield; \
vdst = INST_AA(inst); \
ref = FETCH(1); /* field ref */ \
ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
if (sfield == NULL) { \
EXPORT_PC(); \
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
END_JIT_TSELECT(); \
} \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
UPDATE_FIELD_GET(&sfield->field); \
} \
FINISH(2);
#define HANDLE_SGET_X_JUMBO(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/) \
{ \
StaticField* sfield; \
ref = FETCH(1) | (u4)FETCH(2) << 16; /* field ref */ \
vdst = FETCH(3); \
ILOGV("|sget%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref); \
sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
if (sfield == NULL) { \
EXPORT_PC(); \
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
END_JIT_TSELECT(); \
} \
} \
SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
ILOGV("+ SGET '%s'=0x%08llx", \
sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
UPDATE_FIELD_GET(&sfield->field); \
} \
FINISH(4);
#define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
{ \
StaticField* sfield; \
vdst = INST_AA(inst); \
ref = FETCH(1); /* field ref */ \
ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
if (sfield == NULL) { \
EXPORT_PC(); \
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
END_JIT_TSELECT(); \
} \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
UPDATE_FIELD_PUT(&sfield->field); \
} \
FINISH(2);
#define HANDLE_SPUT_X_JUMBO(_opcode, _opname, _ftype, _regsize) \
HANDLE_OPCODE(_opcode /*vBBBB, class@AAAAAAAA*/) \
{ \
StaticField* sfield; \
ref = FETCH(1) | (u4)FETCH(2) << 16; /* field ref */ \
vdst = FETCH(3); \
ILOGV("|sput%s/jumbo v%d,sfield@0x%08x", (_opname), vdst, ref); \
sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
if (sfield == NULL) { \
EXPORT_PC(); \
sfield = dvmResolveStaticField(curMethod->clazz, ref); \
if (sfield == NULL) \
GOTO_exceptionThrown(); \
if (dvmDexGetResolvedField(methodClassDex, ref) == NULL) { \
END_JIT_TSELECT(); \
} \
} \
dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
ILOGV("+ SPUT '%s'=0x%08llx", \
sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
UPDATE_FIELD_PUT(&sfield->field); \
} \
FINISH(4);