/* this is a standard (no debug support) interpreter */ #define INTERP_TYPE INTERP_STD #define CHECK_DEBUG_AND_PROF() ((void)0) # define CHECK_TRACKED_REFS() ((void)0) /* * In the C mterp stubs, "goto" is a function call followed immediately * by a return. */ #define GOTO_TARGET_DECL(_target, ...) \ void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__); #define GOTO_TARGET(_target, ...) \ void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__) { \ u2 ref, vsrc1, vsrc2, vdst; \ u2 inst = FETCH(0); \ const Method* methodToCall; \ StackSaveArea* debugSaveArea; #define GOTO_TARGET_END } /* * Redefine what used to be local variable accesses into MterpGlue struct * references. (These are undefined down in "footer.c".) */ #define retval glue->retval #define pc glue->pc #define fp glue->fp #define curMethod glue->method #define methodClassDex glue->methodClassDex #define self glue->self #define debugTrackedRefStart glue->debugTrackedRefStart /* ugh */ #define STUB_HACK(x) x /* * Opcode handler framing macros. Here, each opcode is a separate function * that takes a "glue" argument and returns void. We can't declare * these "static" because they may be called from an assembly stub. */ #define HANDLE_OPCODE(_op) \ void dvmMterp_##_op(MterpGlue* glue) { \ u2 ref, vsrc1, vsrc2, vdst; \ u2 inst = FETCH(0); #define OP_END } /* * Like the "portable" FINISH, but don't reload "inst", and return to caller * when done. */ #define FINISH(_offset) { \ ADJUST_PC(_offset); \ CHECK_DEBUG_AND_PROF(); \ CHECK_TRACKED_REFS(); \ return; \ } /* * The "goto label" statements turn into function calls followed by * return statements. Some of the functions take arguments, which in the * portable interpreter are handled by assigning values to globals. */ #define GOTO_exceptionThrown() \ do { \ dvmMterp_exceptionThrown(glue); \ return; \ } while(false) #define GOTO_returnFromMethod() \ do { \ dvmMterp_returnFromMethod(glue); \ return; \ } while(false) #define GOTO_invoke(_target, _methodCallRange) \ do { \ dvmMterp_##_target(glue, _methodCallRange); \ return; \ } while(false) #define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) \ do { \ dvmMterp_invokeMethod(glue, _methodCallRange, _methodToCall, \ _vsrc1, _vdst); \ return; \ } while(false) /* * As a special case, "goto bail" turns into a longjmp. Use "bail_switch" * if we need to switch to the other interpreter upon our return. */ #define GOTO_bail() \ dvmMterpStdBail(glue, false); #define GOTO_bail_switch() \ dvmMterpStdBail(glue, true); /* * Periodically check for thread suspension. * * While we're at it, see if a debugger has attached or the profiler has * started. If so, switch to a different "goto" table. */ #define PERIODIC_CHECKS(_entryPoint, _pcadj) { \ if (dvmCheckSuspendQuick(self)) { \ EXPORT_PC(); /* need for precise GC */ \ dvmCheckSuspendPending(self); \ } \ if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \ ADJUST_PC(_pcadj); \ glue->entryPoint = _entryPoint; \ LOGVV("threadid=%d: switch to STD ep=%d adj=%d\n", \ self->threadId, (_entryPoint), (_pcadj)); \ GOTO_bail_switch(); \ } \ }