Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epidemian
GitHub Repository: epidemian/gravity
Path: blob/master/src/runtime/gravity_vmmacros.h
1214 views
1
//
2
// gravity_vmmacros.h
3
// gravity
4
//
5
// Created by Marco Bambini on 08/10/15.
6
// Copyright © 2015 Creolabs. All rights reserved.
7
//
8
9
#ifndef __GRAVITY_VMMACROS__
10
#define __GRAVITY_VMMACROS__
11
12
// Assertions add significant overhead, so are only enabled in debug builds.
13
#if 1
14
#define ASSERT(condition, message) do { \
15
if (!(condition)) { \
16
fprintf(stderr, "[%s:%d] Assert failed in %s(): %s\n", \
17
__FILE__, __LINE__, __func__, message); \
18
abort(); \
19
} \
20
} \
21
while(0)
22
#else
23
#define ASSERT(condition, message)
24
#endif
25
26
#if 0
27
#define DEBUG_CALL(s, f) printf("%s %s\n", s, f->identifier)
28
#else
29
#define DEBUG_CALL(s, f)
30
#endif
31
32
// signed operation decoding (OPCODE_GET_ONE8bit_SIGN_ONE17bit) from my question on stackoverflow
33
// http://stackoverflow.com/questions/37054769/optimize-a-bit-decoding-operation-in-c?noredirect=1#comment61673505_37054769
34
35
#define OPCODE_GET_OPCODE(op) ((op >> 26) & 0x3F)
36
#define OPCODE_GET_ONE8bit_FLAG_ONE17bit(op,r1,f,n) r1 = (op >> 18) & 0xFF; f = (op >> 17) & 0x01; n = (int32_t)(op & 0x1FFFF)
37
#define OPCODE_GET_ONE8bit_SIGN_ONE17bit(op,r1,n) r1 = (op >> 18) & 0xFF; n = ((int32_t)(op & 0x1FFFF) - (int32_t)(op & 0x20000))
38
#define OPCODE_GET_TWO8bit_ONE10bit(op,r1,r2,r3) r1 = (op >> 18) & 0xFF; r2 = (op >> 10) & 0xFF; r3 = (op & 0x3FF)
39
#define OPCODE_GET_ONE8bit(op,r1) r1 = (op >> 18) & 0xFF;
40
#define OPCODE_GET_SIGN_ONE25bit(op, n) n = ((op >> 25) & 0x01) ? -(op & 0x1FFFFFF) : (op & 0x1FFFFFF)
41
#define OPCODE_GET_ONE8bit_ONE18bit(op,r1,n) r1 = (op >> 18) & 0xFF; n = (op & 0x3FFFF)
42
#define OPCODE_GET_LAST18bit(op,n) n = (op & 0x3FFFF)
43
#define OPCODE_GET_ONE26bit(op, n) n = (op & 0x3FFFFFF)
44
#define OPCODE_GET_ONE8bit_ONE10bit(op,r1,r3) r1 = (op >> 18) & 0xFF; r3 = (op & 0x3FF)
45
#define OPCODE_GET_THREE8bit(op,r1,r2,r3) OPCODE_GET_TWO8bit_ONE10bit(op,r1,r2,r3)
46
#define OPCODE_GET_FOUR8bit(op,r1,r2,r3,r4) r1 = (op >> 24) & 0xFF; r2 = (op >> 16) & 0xFF; r3 = (op >> 8) & 0xFF; r4 = (op & 0xFF)
47
#define OPCODE_GET_THREE8bit_ONE2bit(op,r1,r2,r3,r4) r1 = (op >> 18) & 0xFF; r2 = (op >> 10) & 0xFF; r3 = (op >> 2) & 0xFF; r4 = (op & 0x03)
48
49
#define GRAVITY_VM_DEGUB 0
50
#define GRAVITY_VM_STATS 0
51
#define GRAVITY_GC_STATS 0
52
#define GRAVITY_GC_STRESSTEST 0
53
#define GRAVITY_GC_DEBUG 0
54
#define GRAVITY_STACK_DEBUG 0
55
56
#if GRAVITY_STACK_DEBUG
57
#define DEBUG_STACK() gravity_stack_dump(fiber)
58
#else
59
#define DEBUG_STACK()
60
#endif
61
62
#if GRAVITY_GC_DEBUG
63
#define DEBUG_GC(...) printf(__VA_ARGS__);printf("\n");fflush(stdout)
64
#else
65
#define DEBUG_GC(...)
66
#endif
67
68
#if GRAVITY_VM_DEGUB
69
#define DEBUG_VM(...) DEBUG_STACK();printf("%06u\t",vm->pc); printf(__VA_ARGS__);printf("\n");fflush(stdout)
70
#define DEBUG_VM_NOCR(...) DEBUG_STACK();printf("%06u\t",vm->pc); printf(__VA_ARGS__);fflush(stdout)
71
#define DEBUG_VM_RAW(...) printf(__VA_ARGS__);fflush(stdout)
72
#define INC_PC ++vm->pc;
73
#else
74
#define DEBUG_VM(...)
75
#define DEBUG_VM_NOCR(...)
76
#define DEBUG_VM_RAW(...)
77
#define INC_PC
78
#endif
79
80
#if GRAVITY_VM_STATS
81
#define RESET_STATS(_vm) bzero(_vm->nstat, sizeof(_vm->nstat)); bzero(_vm->tstat, sizeof(_vm->tstat))
82
#define PRINT_STATS(_vm) gravity_vm_stats(_vm)
83
#define START_MICROBENCH(_vm) _vm->t = nanotime()
84
#define UPDATE_STATS(_vm,_op) ++_vm->nstat[_op]; _vm->tstat[_op] += millitime(_vm->t, nanotime())
85
#define STAT_FRAMES_REALLOCATED(_vm) ++_vm->nfrealloc
86
#define STAT_STACK_REALLOCATED(_vm) ++_vm->nsrealloc
87
#else
88
#define RESET_STATS(_vm)
89
#define PRINT_STATS(_vm)
90
#define START_MICROBENCH(_vm)
91
#define UPDATE_STATS(_vm,_op)
92
#define STAT_FRAMES_REALLOCATED(_vm)
93
#define STAT_STACK_REALLOCATED(_vm)
94
#endif
95
96
#define RUNTIME_ERROR(...) do { \
97
report_runtime_error(vm, GRAVITY_ERROR_RUNTIME, __VA_ARGS__); \
98
return false; \
99
} while (0)
100
101
#define RUNTIME_FIBER_ERROR(_err) RUNTIME_ERROR("%s",_err)
102
103
#define RUNTIME_WARNING(...) do { \
104
report_runtime_error(vm, GRAVITY_WARNING, __VA_ARGS__); \
105
} while (0)
106
107
#define SETVALUE_BOOL(idx, x) stackstart[idx]=VALUE_FROM_BOOL(x)
108
#define SETVALUE_INT(idx, x) stackstart[idx]=VALUE_FROM_INT(x)
109
#define SETVALUE_FLOAT(idx, x) stackstart[idx]=VALUE_FROM_FLOAT(x)
110
#define SETVALUE_NULL(idx) stackstart[idx]=VALUE_FROM_NULL
111
#define SETVALUE(idx, x) stackstart[idx]=x
112
#define GETVALUE_INT(v) v.n
113
#define GETVALUE_FLOAT(v) v.f
114
#define STACK_GET(idx) stackstart[idx]
115
// macro the count number of registers needed by the _f function which is the sum of local variables, temp variables and formal parameters
116
#define FN_COUNTREG(_f,_nargs) (MAXNUM(_f->nparams,_nargs) + _f->nlocals + _f->ntemps)
117
118
#if GRAVITY_COMPUTED_GOTO
119
#define DECLARE_DISPATCH_TABLE static void* dispatchTable[] = { \
120
&&RET0, &&HALT, &&NOP, &&RET, \
121
&&CALL, &&LOAD, &&LOADS, &&LOADAT, \
122
&&LOADK, &&LOADG, &&LOADI, &&LOADU, \
123
&&MOVE, &&STORE, &&STOREAT, &&STOREG, \
124
&&STOREU, &&JUMP, &&JUMPF, &&SWITCH, \
125
&&ADD, &&SUB, &&DIV, &&MUL, \
126
&&REM, &&AND, &&OR, &&LT, \
127
&&GT, &&EQ, &&LEQ, &&GEQ, \
128
&&NEQ, &&EQQ, &&NEQQ, &&ISA, \
129
&&MATCH, &&NEG, &&NOT, &&LSHIFT, \
130
&&RSHIFT, &&BAND, &&BOR, &&BXOR, \
131
&&BNOT, &&MAPNEW, &&LISTNEW, &&RANGENEW, \
132
&&SETLIST, &&CLOSURE, &&CLOSE, &&RESERVED1, \
133
&&RESERVED2, &&RESERVED3, &&RESERVED4, &&RESERVED5, \
134
&&RESERVED6 };
135
#define INTERPRET_LOOP DISPATCH();
136
#define CASE_CODE(name) START_MICROBENCH(vm); name
137
#if GRAVITY_VM_STATS
138
#define DISPATCH() DEBUG_STACK();INC_PC;inst = *ip++;op = (opcode_t)OPCODE_GET_OPCODE(inst);UPDATE_STATS(vm,op);goto *dispatchTable[op];
139
#else
140
#define DISPATCH() DEBUG_STACK();INC_PC;inst = *ip++;goto *dispatchTable[op = (opcode_t)OPCODE_GET_OPCODE(inst)];
141
#endif
142
#else
143
#define DECLARE_DISPATCH_TABLE
144
#define INTERPRET_LOOP inst = *ip++;op = (opcode_t)OPCODE_GET_OPCODE(inst);UPDATE_STATS(op);switch (op)
145
#define CASE_CODE(name) case name
146
#define DISPATCH() break
147
#endif
148
149
#define INIT_PARAMS(n) for (uint32_t i=n; i<func->nparams; ++i) \
150
stackstart[i] = VALUE_FROM_UNDEFINED;
151
152
#define STORE_FRAME() frame->ip = ip
153
154
#define LOAD_FRAME() frame = &fiber->frames[fiber->nframes - 1]; \
155
stackstart = frame->stackstart; \
156
ip = frame->ip; \
157
func = frame->closure->f; \
158
DEBUG_VM_RAW("******\tEXEC %s (%p) ******\n", func->identifier, func);
159
160
#define PUSH_FRAME(_c,_n,_r,_p) gravity_callframe_t *cframe = gravity_new_callframe(vm, fiber); \
161
cframe->closure = _c; \
162
cframe->stackstart = _n; \
163
cframe->ip = _c->f->bytecode; \
164
cframe->dest = _r; \
165
cframe->nargs = _p; \
166
cframe->outloop = false; \
167
cframe->args = (_c->f->useargs) ? gravity_list_from_array(vm, _p-1, _n+1) : NULL; \
168
169
#define SYNC_STACKTOP(_c,_n) if (_c->f->tag != EXEC_TYPE_NATIVE) fiber->stacktop -= _n
170
#define SETFRAME_OUTLOOP(cframe) (cframe)->outloop = true
171
172
#define COMPUTE_JUMP(value) (func->bytecode + (value))
173
174
// FAST MATH MACROS
175
#define FMATH_BIN_INT(_r1,_v2,_v3,_OP) do {SETVALUE(_r1, VALUE_FROM_INT(_v2 _OP _v3)); DISPATCH();} while(0)
176
#define FMATH_BIN_FLOAT(_r1,_v2,_v3,_OP) do {SETVALUE(_r1, VALUE_FROM_FLOAT(_v2 _OP _v3)); DISPATCH();} while(0)
177
#define FMATH_BIN_BOOL(_r1,_v2,_v3,_OP) do {SETVALUE(_r1, VALUE_FROM_BOOL(_v2 _OP _v3)); DISPATCH();} while(0)
178
179
#define DEFINE_STACK_VARIABLE(_v,_r) register gravity_value_t _v = STACK_GET(_r)
180
#define DEFINE_INDEX_VARIABLE(_v,_r) register gravity_value_t _v = (_r < MAX_REGISTERS) ? STACK_GET(_r) : VALUE_FROM_INT(_r-MAX_REGISTERS)
181
182
#define NO_CHECK
183
#define CHECK_ZERO(_v) if ((VALUE_ISA_INT(_v) && (_v.n == 0)) || (VALUE_ISA_FLOAT(_v) && (_v.f == 0.0))) \
184
RUNTIME_ERROR("Division by 0 error.")
185
186
#define CHECK_FAST_BINARY_BOOL(r1,r2,r3,v2,v3,OP) DEFINE_STACK_VARIABLE(v2,r2); \
187
DEFINE_STACK_VARIABLE(v3,r3); \
188
if (VALUE_ISA_BOOL(v2) && VALUE_ISA_BOOL(v3)) FMATH_BIN_BOOL(r1, v2.n, v3.n, OP);
189
190
#define CHECK_FAST_UNARY_BOOL(r1,r2,v2,OP) DEFINE_STACK_VARIABLE(v2,r2); \
191
if (VALUE_ISA_BOOL(v2)) {SETVALUE(r1, VALUE_FROM_BOOL(OP v2.n)); DISPATCH();}
192
193
// fast math only for INT and FLOAT
194
#define CHECK_FAST_BINARY_MATH(r1,r2,r3,v2,v3,OP,_CHECK) \
195
DEFINE_STACK_VARIABLE(v2,r2); \
196
DEFINE_STACK_VARIABLE(v3,r3); \
197
_CHECK; \
198
if (VALUE_ISA_INT(v2)) { \
199
if (VALUE_ISA_INT(v3)) FMATH_BIN_INT(r1, v2.n, v3.n, OP); \
200
if (VALUE_ISA_FLOAT(v3)) FMATH_BIN_FLOAT(r1, v2.n, v3.f, OP); \
201
} else if (VALUE_ISA_FLOAT(v2)) { \
202
if (VALUE_ISA_FLOAT(v3)) FMATH_BIN_FLOAT(r1, v2.f, v3.f, OP); \
203
if (VALUE_ISA_INT(v3)) FMATH_BIN_FLOAT(r1, v2.f, v3.n, OP); \
204
}
205
206
#define CHECK_FAST_UNARY_MATH(r1,r2,v2,OP) DEFINE_STACK_VARIABLE(v2,r2); \
207
if (VALUE_ISA_INT(v2)) {SETVALUE(r1, VALUE_FROM_INT(OP v2.n)); DISPATCH();} \
208
if (VALUE_ISA_FLOAT(v2)) {SETVALUE(r1, VALUE_FROM_FLOAT(OP v2.f)); DISPATCH();}
209
210
211
#define CHECK_FAST_BINARY_REM(r1,r2,r3,v2,v3) DEFINE_STACK_VARIABLE(v2,r2); \
212
DEFINE_STACK_VARIABLE(v3,r3); \
213
if (VALUE_ISA_INT(v2) && VALUE_ISA_INT(v3)) FMATH_BIN_INT(r1, v2.n, v3.n, %);
214
215
#define CHECK_FAST_BINARY_BIT(r1,r2,r3,v2,v3,OP) DEFINE_STACK_VARIABLE(v2,r2); \
216
DEFINE_STACK_VARIABLE(v3,r3); \
217
if (VALUE_ISA_INT(v2) && VALUE_ISA_INT(v3)) FMATH_BIN_INT(r1, v2.n, v3.n, OP);
218
219
#define DECODE_BINARY_OPERATION(r1,r2,r3) OPCODE_GET_TWO8bit_ONE10bit(inst, const uint32_t r1, const uint32_t r2, const uint32_t r3); \
220
DEBUG_VM("%s %d %d %d", opcode_name(op), r1, r2, r3)
221
222
#define PREPARE_FUNC_CALLN(_c,_i,_w,_N) gravity_closure_t *_c = (gravity_closure_t *)gravity_class_lookup_closure(gravity_value_getclass(v2), cache[_i]); \
223
if (!_c || !_c->f) RUNTIME_ERROR("Unable to perform operator %s on object", opcode_name(op)); \
224
uint32_t _w = FN_COUNTREG(func, frame->nargs); \
225
uint32_t _rneed = FN_COUNTREG(_c->f, _N); \
226
gravity_check_stack(vm, fiber, _rneed, &stackstart)
227
228
#define PREPARE_FUNC_CALL1(_c,_v1,_i,_w) PREPARE_FUNC_CALLN(_c,_i,_w,1); \
229
SETVALUE(_w, _v1)
230
231
232
#define PREPARE_FUNC_CALL2(_c,_v1,_v2,_i,_w) PREPARE_FUNC_CALLN(_c,_i,_w,2); \
233
SETVALUE(_w, _v1); \
234
SETVALUE(_w+1, _v2)
235
236
#define PREPARE_FUNC_CALL3(_c,_v1,_v2,_v3,_i,_w) PREPARE_FUNC_CALLN(_c,_i,_w,3); \
237
SETVALUE(_w, _v1); \
238
SETVALUE(_w+1, _v2); \
239
SETVALUE(_w+2, _v3)
240
241
242
#define CALL_FUNC(_name,_c,r1,nargs,rwin) STORE_FRAME(); \
243
execute_op_##_name: \
244
switch(_c->f->tag) { \
245
case EXEC_TYPE_NATIVE: { \
246
PUSH_FRAME(_c, &stackstart[rwin], r1, nargs); \
247
} break; \
248
case EXEC_TYPE_INTERNAL: { \
249
if (!_c->f->internal(vm, &stackstart[rwin], nargs, r1)) { \
250
if (VALUE_ISA_CLOSURE(STACK_GET(r1))) { \
251
closure = VALUE_AS_CLOSURE(STACK_GET(r1)); \
252
SETVALUE(r1, VALUE_FROM_NULL); \
253
goto execute_op_##_name; \
254
} \
255
fiber = vm->fiber; \
256
if (fiber == NULL) return true; \
257
if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error); \
258
} \
259
} break; \
260
case EXEC_TYPE_BRIDGED: { \
261
ASSERT(delegate->bridge_execute, "bridge_execute delegate callback is mandatory"); \
262
if (!delegate->bridge_execute(vm, _c->f->xdata, &stackstart[rwin], nargs, r1)) { \
263
if (fiber->error) RUNTIME_FIBER_ERROR(fiber->error); \
264
} \
265
} break; \
266
case EXEC_TYPE_SPECIAL: \
267
RUNTIME_ERROR("Unable to handle a special function in current context"); \
268
break; \
269
} \
270
LOAD_FRAME(); \
271
SYNC_STACKTOP(_c, _rneed)
272
273
#endif
274
275