1 | /* |
2 | ** Instruction dispatch handling. |
3 | ** Copyright (C) 2005-2014 Mike Pall. See Copyright Notice in luajit.h |
4 | */ |
5 | |
6 | #ifndef _LJ_DISPATCH_H |
7 | #define _LJ_DISPATCH_H |
8 | |
9 | #include "lj_obj.h" |
10 | #include "lj_bc.h" |
11 | #if LJ_HASJIT |
12 | #include "lj_jit.h" |
13 | #endif |
14 | |
15 | #if LJ_TARGET_MIPS |
16 | /* Need our own global offset table for the dreaded MIPS calling conventions. */ |
17 | #if LJ_HASJIT |
18 | #define JITGOTDEF(_) _(lj_trace_exit) _(lj_trace_hot) |
19 | #else |
20 | #define JITGOTDEF(_) |
21 | #endif |
22 | #if LJ_HASFFI |
23 | #define FFIGOTDEF(_) \ |
24 | _(lj_meta_equal_cd) _(lj_ccallback_enter) _(lj_ccallback_leave) |
25 | #else |
26 | #define FFIGOTDEF(_) |
27 | #endif |
28 | #define GOTDEF(_) \ |
29 | _(floor) _(ceil) _(trunc) _(log) _(log10) _(exp) _(sin) _(cos) _(tan) \ |
30 | _(asin) _(acos) _(atan) _(sinh) _(cosh) _(tanh) _(frexp) _(modf) _(atan2) \ |
31 | _(pow) _(fmod) _(ldexp) \ |
32 | _(lj_dispatch_call) _(lj_dispatch_ins) _(lj_err_throw) \ |
33 | _(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \ |
34 | _(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \ |
35 | _(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \ |
36 | _(lj_meta_for) _(lj_meta_len) _(lj_meta_tget) _(lj_meta_tset) \ |
37 | _(lj_state_growstack) _(lj_str_fromnum) _(lj_str_fromnumber) _(lj_str_new) \ |
38 | _(lj_tab_dup) _(lj_tab_get) _(lj_tab_getinth) _(lj_tab_len) _(lj_tab_new) \ |
39 | _(lj_tab_newkey) _(lj_tab_next) _(lj_tab_reasize) \ |
40 | JITGOTDEF(_) FFIGOTDEF(_) |
41 | |
42 | enum { |
43 | #define GOTENUM(name) LJ_GOT_##name, |
44 | GOTDEF(GOTENUM) |
45 | #undef GOTENUM |
46 | LJ_GOT__MAX |
47 | }; |
48 | #endif |
49 | |
50 | /* Type of hot counter. Must match the code in the assembler VM. */ |
51 | /* 16 bits are sufficient. Only 0.0015% overhead with maximum slot penalty. */ |
52 | typedef uint16_t HotCount; |
53 | |
54 | /* Number of hot counter hash table entries (must be a power of two). */ |
55 | #define HOTCOUNT_SIZE 64 |
56 | #define HOTCOUNT_PCMASK ((HOTCOUNT_SIZE-1)*sizeof(HotCount)) |
57 | |
58 | /* Hotcount decrements. */ |
59 | #define HOTCOUNT_LOOP 2 |
60 | #define HOTCOUNT_CALL 1 |
61 | |
62 | /* This solves a circular dependency problem -- bump as needed. Sigh. */ |
63 | #define GG_NUM_ASMFF 62 |
64 | |
65 | #define GG_LEN_DDISP (BC__MAX + GG_NUM_ASMFF) |
66 | #define GG_LEN_SDISP BC_FUNCF |
67 | #define GG_LEN_DISP (GG_LEN_DDISP + GG_LEN_SDISP) |
68 | |
69 | /* Global state, main thread and extra fields are allocated together. */ |
70 | typedef struct GG_State { |
71 | lua_State L; /* Main thread. */ |
72 | global_State g; /* Global state. */ |
73 | #if LJ_TARGET_MIPS |
74 | ASMFunction got[LJ_GOT__MAX]; /* Global offset table. */ |
75 | #endif |
76 | #if LJ_HASJIT |
77 | jit_State J; /* JIT state. */ |
78 | HotCount hotcount[HOTCOUNT_SIZE]; /* Hot counters. */ |
79 | #endif |
80 | ASMFunction dispatch[GG_LEN_DISP]; /* Instruction dispatch tables. */ |
81 | BCIns bcff[GG_NUM_ASMFF]; /* Bytecode for ASM fast functions. */ |
82 | } GG_State; |
83 | |
84 | #define GG_OFS(field) ((int)offsetof(GG_State, field)) |
85 | #define G2GG(gl) ((GG_State *)((char *)(gl) - GG_OFS(g))) |
86 | #define J2GG(j) ((GG_State *)((char *)(j) - GG_OFS(J))) |
87 | #define L2GG(L) (G2GG(G(L))) |
88 | #define J2G(J) (&J2GG(J)->g) |
89 | #define G2J(gl) (&G2GG(gl)->J) |
90 | #define L2J(L) (&L2GG(L)->J) |
91 | #define GG_G2DISP (GG_OFS(dispatch) - GG_OFS(g)) |
92 | #define GG_DISP2G (GG_OFS(g) - GG_OFS(dispatch)) |
93 | #define GG_DISP2J (GG_OFS(J) - GG_OFS(dispatch)) |
94 | #define GG_DISP2HOT (GG_OFS(hotcount) - GG_OFS(dispatch)) |
95 | #define GG_DISP2STATIC (GG_LEN_DDISP*(int)sizeof(ASMFunction)) |
96 | |
97 | #define hotcount_get(gg, pc) \ |
98 | (gg)->hotcount[(u32ptr(pc)>>2) & (HOTCOUNT_SIZE-1)] |
99 | #define hotcount_set(gg, pc, val) \ |
100 | (hotcount_get((gg), (pc)) = (HotCount)(val)) |
101 | |
102 | /* Dispatch table management. */ |
103 | LJ_FUNC void lj_dispatch_init(GG_State *GG); |
104 | #if LJ_HASJIT |
105 | LJ_FUNC void lj_dispatch_init_hotcount(global_State *g); |
106 | #endif |
107 | LJ_FUNC void lj_dispatch_update(global_State *g); |
108 | |
109 | /* Instruction dispatch callback for hooks or when recording. */ |
110 | LJ_FUNCA void LJ_FASTCALL lj_dispatch_ins(lua_State *L, const BCIns *pc); |
111 | LJ_FUNCA ASMFunction LJ_FASTCALL lj_dispatch_call(lua_State *L, const BCIns*pc); |
112 | LJ_FUNCA void LJ_FASTCALL lj_dispatch_return(lua_State *L, const BCIns *pc); |
113 | |
114 | #if LJ_HASFFI && !defined(_BUILDVM_H) |
115 | /* Save/restore errno and GetLastError() around hooks, exits and recording. */ |
116 | #include <errno.h> |
117 | #if LJ_TARGET_WINDOWS |
118 | #define WIN32_LEAN_AND_MEAN |
119 | #include <windows.h> |
120 | #define ERRNO_SAVE int olderr = errno; DWORD oldwerr = GetLastError(); |
121 | #define ERRNO_RESTORE errno = olderr; SetLastError(oldwerr); |
122 | #else |
123 | #define ERRNO_SAVE int olderr = errno; |
124 | #define ERRNO_RESTORE errno = olderr; |
125 | #endif |
126 | #else |
127 | #define ERRNO_SAVE |
128 | #define ERRNO_RESTORE |
129 | #endif |
130 | |
131 | #endif |
132 | |