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