summaryrefslogtreecommitdiff
path: root/vm/mterp/cstubs/stubdefs.cpp
blob: 0bffd49f139ec5a3f663a44aa5c103e619aee6a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
 * In the C mterp stubs, "goto" is a function call followed immediately
 * by a return.
 */

#define GOTO_TARGET_DECL(_target, ...)                                      \
    extern "C" void dvmMterp_##_target(Thread* self, ## __VA_ARGS__);

/* (void)xxx to quiet unused variable compiler warnings. */
#define GOTO_TARGET(_target, ...)                                           \
    void dvmMterp_##_target(Thread* self, ## __VA_ARGS__) {                 \
        u2 ref, vsrc1, vsrc2, vdst;                                         \
        u2 inst = FETCH(0);                                                 \
        const Method* methodToCall;                                         \
        StackSaveArea* debugSaveArea;                                       \
        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;        \
        (void)methodToCall; (void)debugSaveArea;

#define GOTO_TARGET_END }

/*
 * Redefine what used to be local variable accesses into Thread struct
 * references.  (These are undefined down in "footer.cpp".)
 */
#define retval                  self->interpSave.retval
#define pc                      self->interpSave.pc
#define fp                      self->interpSave.curFrame
#define curMethod               self->interpSave.method
#define methodClassDex          self->interpSave.methodClassDex
#define debugTrackedRefStart    self->interpSave.debugTrackedRefStart

/* ugh */
#define STUB_HACK(x) x
#if defined(WITH_JIT)
#define JIT_STUB_HACK(x) x
#else
#define JIT_STUB_HACK(x)
#endif

/*
 * InterpSave's pc and fp must be valid when breaking out to a
 * "Reportxxx" routine.  Because the portable interpreter uses local
 * variables for these, we must flush prior.  Stubs, however, use
 * the interpSave vars directly, so this is a nop for stubs.
 */
#define PC_FP_TO_SELF()
#define PC_TO_SELF()

/*
 * Opcode handler framing macros.  Here, each opcode is a separate function
 * that takes a "self" argument and returns void.  We can't declare
 * these "static" because they may be called from an assembly stub.
 * (void)xxx to quiet unused variable compiler warnings.
 */
#define HANDLE_OPCODE(_op)                                                  \
    extern "C" void dvmMterp_##_op(Thread* self);                           \
    void dvmMterp_##_op(Thread* self) {                                     \
        u4 ref;                                                             \
        u2 vsrc1, vsrc2, vdst;                                              \
        u2 inst = FETCH(0);                                                 \
        (void)ref; (void)vsrc1; (void)vsrc2; (void)vdst; (void)inst;

#define OP_END }

/*
 * Like the "portable" FINISH, but don't reload "inst", and return to caller
 * when done.  Further, debugger/profiler checks are handled
 * before handler execution in mterp, so we don't do them here either.
 */
#if defined(WITH_JIT)
#define FINISH(_offset) {                                                   \
        ADJUST_PC(_offset);                                                 \
        if (self->interpBreak.ctl.subMode & kSubModeJitTraceBuild) {        \
            dvmCheckJit(pc, self);                                          \
        }                                                                   \
        return;                                                             \
    }
#else
#define FINISH(_offset) {                                                   \
        ADJUST_PC(_offset);                                                 \
        return;                                                             \
    }
#endif


/*
 * 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(self);                                     \
        return;                                                             \
    } while(false)

#define GOTO_returnFromMethod()                                             \
    do {                                                                    \
        dvmMterp_returnFromMethod(self);                                    \
        return;                                                             \
    } while(false)

#define GOTO_invoke(_target, _methodCallRange, _jumboFormat)                \
    do {                                                                    \
        dvmMterp_##_target(self, _methodCallRange, _jumboFormat);           \
        return;                                                             \
    } while(false)

#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
    do {                                                                    \
        dvmMterp_invokeMethod(self, _methodCallRange, _methodToCall,        \
            _vsrc1, _vdst);                                                 \
        return;                                                             \
    } while(false)

/*
 * As a special case, "goto bail" turns into a longjmp.
 */
#define GOTO_bail()                                                         \
    dvmMterpStdBail(self, false);

/*
 * Periodically check for thread suspension.
 *
 * While we're at it, see if a debugger has attached or the profiler has
 * started.
 */
#define PERIODIC_CHECKS(_pcadj) {                              \
        if (dvmCheckSuspendQuick(self)) {                                   \
            EXPORT_PC();  /* need for precise GC */                         \
            dvmCheckSuspendPending(self);                                   \
        }                                                                   \
    }