| /* forward declarations of goto targets */ |
| GOTO_TARGET_DECL(filledNewArray, bool methodCallRange); |
| GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange); |
| GOTO_TARGET_DECL(invokeSuper, bool methodCallRange); |
| GOTO_TARGET_DECL(invokeInterface, bool methodCallRange); |
| GOTO_TARGET_DECL(invokeDirect, bool methodCallRange); |
| GOTO_TARGET_DECL(invokeStatic, bool methodCallRange); |
| GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange); |
| GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange); |
| 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", 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(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(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( \ |
| arrayObj->length, GET_REGISTER(vsrc2)); \ |
| GOTO_exceptionThrown(); \ |
| } \ |
| SET_REGISTER##_regsize(vdst, \ |
| ((_type*)(void*)arrayObj->contents)[GET_REGISTER(vsrc2)]); \ |
| ILOGV("+ AGET[%d]=%#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( \ |
| arrayObj->length, GET_REGISTER(vsrc2)); \ |
| GOTO_exceptionThrown(); \ |
| } \ |
| ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\ |
| ((_type*)(void*)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->name, \ |
| (u8) GET_REGISTER##_regsize(vdst)); \ |
| } \ |
| FINISH(2); |
| |
| #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->name, \ |
| (u8) GET_REGISTER##_regsize(vdst)); \ |
| } \ |
| FINISH(2); |
| |
| #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. |
| * Because the portable interpreter is not involved with the JIT |
| * and trace building, we only need the extra check here when this |
| * code is massaged into a stub called from an assembly interpreter. |
| * This is controlled by the JIT_STUB_HACK maco. |
| */ |
| |
| #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) { \ |
| JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc)); \ |
| } \ |
| } \ |
| SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \ |
| ILOGV("+ SGET '%s'=0x%08llx", \ |
| sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \ |
| } \ |
| FINISH(2); |
| |
| #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) { \ |
| JIT_STUB_HACK(dvmJitEndTraceSelect(self,pc)); \ |
| } \ |
| } \ |
| dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \ |
| ILOGV("+ SPUT '%s'=0x%08llx", \ |
| sfield->name, (u8)GET_REGISTER##_regsize(vdst)); \ |
| } \ |
| FINISH(2); |