| HANDLE_OPCODE(OP_EXECUTE_INLINE /*vB, {vD, vE, vF, vG}, inline@CCCC*/) |
| { |
| /* |
| * This has the same form as other method calls, but we ignore |
| * the 5th argument (vA). This is chiefly because the first four |
| * arguments to a function on ARM are in registers. |
| * |
| * We only set the arguments that are actually used, leaving |
| * the rest uninitialized. We're assuming that, if the method |
| * needs them, they'll be specified in the call. |
| * |
| * However, this annoys gcc when optimizations are enabled, |
| * causing a "may be used uninitialized" warning. Quieting |
| * the warnings incurs a slight penalty (5%: 373ns vs. 393ns |
| * on empty method). Note that valgrind is perfectly happy |
| * either way as the uninitialiezd values are never actually |
| * used. |
| */ |
| u4 arg0, arg1, arg2, arg3; |
| arg0 = arg1 = arg2 = arg3 = 0; |
| |
| EXPORT_PC(); |
| |
| vsrc1 = INST_B(inst); /* #of args */ |
| ref = FETCH(1); /* inline call "ref" */ |
| vdst = FETCH(2); /* 0-4 register indices */ |
| ILOGV("|execute-inline args=%d @%d {regs=0x%04x}", |
| vsrc1, ref, vdst); |
| |
| assert((vdst >> 16) == 0); // 16-bit type -or- high 16 bits clear |
| assert(vsrc1 <= 4); |
| |
| switch (vsrc1) { |
| case 4: |
| arg3 = GET_REGISTER(vdst >> 12); |
| /* fall through */ |
| case 3: |
| arg2 = GET_REGISTER((vdst & 0x0f00) >> 8); |
| /* fall through */ |
| case 2: |
| arg1 = GET_REGISTER((vdst & 0x00f0) >> 4); |
| /* fall through */ |
| case 1: |
| arg0 = GET_REGISTER(vdst & 0x0f); |
| /* fall through */ |
| default: // case 0 |
| ; |
| } |
| |
| if (self->interpBreak.ctl.subMode & kSubModeDebuggerActive) { |
| if (!dvmPerformInlineOp4Dbg(arg0, arg1, arg2, arg3, &retval, ref)) |
| GOTO_exceptionThrown(); |
| } else { |
| if (!dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)) |
| GOTO_exceptionThrown(); |
| } |
| } |
| FINISH(3); |
| OP_END |