1 /* this is a standard (no debug support) interpreter */ 2 #define INTERP_TYPE INTERP_STD 3 #define CHECK_DEBUG_AND_PROF() ((void)0) 4 # define CHECK_TRACKED_REFS() ((void)0) 5 6 /* 7 * In the C mterp stubs, "goto" is a function call followed immediately 8 * by a return. 9 */ 10 11 #define GOTO_TARGET_DECL(_target, ...) \ 12 void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__); 13 14 #define GOTO_TARGET(_target, ...) \ 15 void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__) { \ 16 u2 ref, vsrc1, vsrc2, vdst; \ 17 u2 inst = FETCH(0); \ 18 const Method* methodToCall; \ 19 StackSaveArea* debugSaveArea; 20 21 #define GOTO_TARGET_END } 22 23 /* 24 * Redefine what used to be local variable accesses into MterpGlue struct 25 * references. (These are undefined down in "footer.c".) 26 */ 27 #define retval glue->retval 28 #define pc glue->pc 29 #define fp glue->fp 30 #define curMethod glue->method 31 #define methodClassDex glue->methodClassDex 32 #define self glue->self 33 #define debugTrackedRefStart glue->debugTrackedRefStart 34 35 /* ugh */ 36 #define STUB_HACK(x) x 37 38 39 /* 40 * Opcode handler framing macros. Here, each opcode is a separate function 41 * that takes a "glue" argument and returns void. We can't declare 42 * these "static" because they may be called from an assembly stub. 43 */ 44 #define HANDLE_OPCODE(_op) \ 45 void dvmMterp_##_op(MterpGlue* glue) { \ 46 u2 ref, vsrc1, vsrc2, vdst; \ 47 u2 inst = FETCH(0); 48 49 #define OP_END } 50 51 /* 52 * Like the "portable" FINISH, but don't reload "inst", and return to caller 53 * when done. 54 */ 55 #define FINISH(_offset) { \ 56 ADJUST_PC(_offset); \ 57 CHECK_DEBUG_AND_PROF(); \ 58 CHECK_TRACKED_REFS(); \ 59 return; \ 60 } 61 62 63 /* 64 * The "goto label" statements turn into function calls followed by 65 * return statements. Some of the functions take arguments, which in the 66 * portable interpreter are handled by assigning values to globals. 67 */ 68 69 #define GOTO_exceptionThrown() \ 70 do { \ 71 dvmMterp_exceptionThrown(glue); \ 72 return; \ 73 } while(false) 74 75 #define GOTO_returnFromMethod() \ 76 do { \ 77 dvmMterp_returnFromMethod(glue); \ 78 return; \ 79 } while(false) 80 81 #define GOTO_invoke(_target, _methodCallRange) \ 82 do { \ 83 dvmMterp_##_target(glue, _methodCallRange); \ 84 return; \ 85 } while(false) 86 87 #define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) \ 88 do { \ 89 dvmMterp_invokeMethod(glue, _methodCallRange, _methodToCall, \ 90 _vsrc1, _vdst); \ 91 return; \ 92 } while(false) 93 94 /* 95 * As a special case, "goto bail" turns into a longjmp. Use "bail_switch" 96 * if we need to switch to the other interpreter upon our return. 97 */ 98 #define GOTO_bail() \ 99 dvmMterpStdBail(glue, false); 100 #define GOTO_bail_switch() \ 101 dvmMterpStdBail(glue, true); 102 103 /* 104 * Periodically check for thread suspension. 105 * 106 * While we're at it, see if a debugger has attached or the profiler has 107 * started. If so, switch to a different "goto" table. 108 */ 109 #define PERIODIC_CHECKS(_entryPoint, _pcadj) { \ 110 dvmCheckSuspendQuick(self); \ 111 if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \ 112 ADJUST_PC(_pcadj); \ 113 glue->entryPoint = _entryPoint; \ 114 LOGVV("threadid=%d: switch to STD ep=%d adj=%d\n", \ 115 glue->self->threadId, (_entryPoint), (_pcadj)); \ 116 GOTO_bail_switch(); \ 117 } \ 118 } 119 120