This repository has been archived by the owner on Aug 18, 2018. It is now read-only.
/
jroot.h
197 lines (171 loc) · 5.41 KB
/
jroot.h
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#ifndef JOHNSON_JROOT_H
#define JOHNSON_JROOT_H
#define _JROOT_NAMESIZE 200L
#define _JROOT_ERRSIZE 500L
#define _JROOT_ROOT (void*)(1)
#define OUR_CONTEXT(js_context) \
({ \
JohnsonContext* _context; \
const VALUE _ruby_context = (VALUE)JS_GetContextPrivate(js_context); \
Data_Get_Struct(_ruby_context, JohnsonContext, _context); \
_context; \
})
#define OUR_RUNTIME(js_context) \
({ \
JohnsonRuntime* _johnson_runtime; \
JSRuntime * _js_runtime = JS_GetRuntime(js_context);\
const VALUE _ruby_runtime = (VALUE)JS_GetRuntimePrivate(_js_runtime); \
Data_Get_Struct(_ruby_runtime, JohnsonRuntime, _johnson_runtime); \
_johnson_runtime; \
})
#define _PREPARE_JROOTS(rb, context, cleancount) \
const bool _jroot_ruby = (rb); \
const int _jroot_cleans = (cleancount); \
void (*_jroot_cleanup[_jroot_cleans])(JSContext*, void*); \
void* _jroot_cleanup_data[_jroot_cleans]; \
JSContext* const _jroot_context = (context); \
int _jroot_cleanidx = 0;
#define PREPARE_JROOTS(context, cleancount) \
_PREPARE_JROOTS(false, context, cleancount)
#define PREPARE_RUBY_JROOTS(context, cleancount) \
_PREPARE_JROOTS(true, context, cleancount)
#define JCLEANUP(func, data) \
do \
{ \
assert(_jroot_cleanidx < _jroot_cleans); \
_jroot_cleanup[_jroot_cleanidx] = (func); \
_jroot_cleanup_data[_jroot_cleanidx] = (data); \
_jroot_cleanidx++; \
} while(0)
#define _JROOT(ptr, name) \
do \
{ \
static char _name[_JROOT_NAMESIZE] = ""; \
void* const _root = (ptr); \
if (*_name == '\0') \
snprintf(_name, _JROOT_NAMESIZE, "%s[%d]:%s: %s", __FILE__, __LINE__, __func__, (name)); \
JCHECK(JS_AddNamedRoot(_jroot_context, _root, _name)); \
JCLEANUP(_JROOT_ROOT, _root); \
} while(0)
#define JROOT(var) _JROOT(&(var), #var)
#define JROOT_PTR(ptr) _JROOT(ptr, #ptr)
#define JUNROOT(var) \
do \
{ \
void* const _jroot_match = &(var); \
int _jroot_i; \
for (_jroot_i = _jroot_cleanidx - 1; _jroot_i >= 0; _jroot_i--) \
if (_jroot_cleanup[_jroot_i] == _JROOT_ROOT && _jroot_cleanup_data[_jroot_i] == _jroot_match) \
{ \
JS_RemoveRoot(_jroot_context, _jroot_cleanup_data[_jroot_i]); \
if (_jroot_i == _jroot_cleanidx - 1) _jroot_cleanidx--; \
_jroot_cleanup[_jroot_i] = NULL; \
} \
} while (0)
#define REMOVE_JROOTS \
do \
{ \
int _jroot_i; \
for (_jroot_i = _jroot_cleanidx - 1; _jroot_i >= 0; _jroot_i--) \
{ \
if (_jroot_cleanup[_jroot_i] == _JROOT_ROOT) \
JS_RemoveRoot(_jroot_context, _jroot_cleanup_data[_jroot_i]); \
else if (_jroot_cleanup[_jroot_i]) \
(_jroot_cleanup[_jroot_i])(_jroot_context, _jroot_cleanup_data[_jroot_i]); \
} \
} while (0)
#define JCHECK_RUBY(cond) \
do \
{ \
assert(_jroot_ruby); \
if (!(cond)) \
{ \
REMOVE_JROOTS; \
raise_js_error_in_ruby(OUR_RUNTIME(_jroot_context)); \
} \
} while (0)
#define JCHECK(cond) \
do \
{ \
if (!(cond)) \
{ \
REMOVE_JROOTS; \
if (_jroot_ruby) \
raise_js_error_in_ruby(OUR_RUNTIME(_jroot_context)); \
else \
return JS_FALSE; \
} \
} while (0)
#define JPROTECT(func, data) \
({ \
int _state; \
const VALUE _old_errinfo = ruby_errinfo; \
const VALUE _result = rb_protect((func), (data), &_state); \
if (_state) \
{ \
REMOVE_JROOTS; \
if (_jroot_ruby) \
rb_jump_tag(_state); \
else \
return report_ruby_error_in_js(OUR_RUNTIME(_jroot_context), _state, _old_errinfo); \
} \
_result; \
})
#define JRETURN \
do \
{ \
assert(!_jroot_ruby); \
REMOVE_JROOTS; \
return JS_TRUE; \
} while(0)
#define JRETURN_RUBY(value) \
do \
{ \
assert(_jroot_ruby); \
typeof(value) _jroot_result = (value); \
REMOVE_JROOTS; \
return _jroot_result; \
} while(0)
#define JERROR(format, args...) \
do \
{ \
char _jroot_msg[_JROOT_ERRSIZE]; \
snprintf(_jroot_msg, _JROOT_ERRSIZE, (format) , ## args); \
if (_jroot_ruby) \
{ \
REMOVE_JROOTS; \
rb_raise(rb_eRuntimeError, _jroot_msg); \
} \
else \
{ \
JSString* _jroot_err_str = JS_NewStringCopyZ(_jroot_context, _jroot_msg); \
if (_jroot_err_str) JS_SetPendingException(_jroot_context, STRING_TO_JSVAL(_jroot_err_str)); \
REMOVE_JROOTS; \
return JS_FALSE; \
} \
} while(0)
#define ARGLIST1(a) _data->a
#define ARGLIST2(a, b) _data->a, _data->b
#define ARGLIST3(a, b, c) _data->a, _data->b, _data->c
#define ARGLIST4(a, b, c, d) _data->a, _data->b, _data->c, _data->d
#define ARGLIST5(a, b, c, d, e) _data->a, _data->b, _data->c, _data->d, _data->e
#define DECLARE_RUBY_WRAPPER(name, args) \
typedef struct { args; } name ## _args; \
VALUE name ## _invoke(VALUE magic);
#define DEFINE_RUBY_WRAPPER(name, func, arglist) \
VALUE name ## _invoke(VALUE magic) \
{ \
name ## _args * _data = (name ## _args *)(FIX2LONG(magic) << 2); \
return func(arglist); \
}
#define DEFINE_VOID_RUBY_WRAPPER(name, func, arglist) \
VALUE name ## _invoke(VALUE magic) \
{ \
name ## _args * _data = (name ## _args *)(FIX2LONG(magic) << 2); \
func(arglist); \
return Qnil; \
}
#define RUBY_WRAPPER_ARG(name, args...) ({ name ## _args _x = { args }; LONG2FIX((long)(&_x) >> 2); })
#define RUBY_WRAPPER(name) name ## _invoke
#define CALL_RUBY_WRAPPER(name, args...) JPROTECT(RUBY_WRAPPER(name), RUBY_WRAPPER_ARG(name, args))
#endif