1 /*
2  * Copyright 2017 The Emscripten Authors.  All rights reserved.
3  * Emscripten is available under two separate licenses, the MIT license and the
4  * University of Illinois/NCSA Open Source License.  Both these licenses can be
5  * found in the LICENSE file.
6  */
7 
8 #pragma once
9 
10 // EM_ASM does not work strict C mode.
11 #if !defined(__cplusplus) && defined(__STRICT_ANSI__)
12 
13 #define EM_ASM_ERROR _Pragma("GCC error(\"EM_ASM does not work in -std=c* modes, use -std=gnu* modes instead\")")
14 #define EM_ASM(...) EM_ASM_ERROR
15 #define EM_ASM_INT(...) EM_ASM_ERROR
16 #define EM_ASM_DOUBLE(...) EM_ASM_ERROR
17 #define MAIN_THREAD_EM_ASM(...) EM_ASM_ERROR
18 #define MAIN_THREAD_EM_ASM_INT(...) EM_ASM_ERROR
19 #define MAIN_THREAD_EM_ASM_DOUBLE(...) EM_ASM_ERROR
20 #define MAIN_THREAD_ASYNC_EM_ASM(...) EM_ASM_ERROR
21 #define EM_ASM_(...) EM_ASM_ERROR
22 #define EM_ASM_ARGS(...) EM_ASM_ERROR
23 #define EM_ASM_INT_V(...) EM_ASM_ERROR
24 #define EM_ASM_DOUBLE_V(...) EM_ASM_ERROR
25 
26 #else
27 
28 #ifndef __asmjs__
29 // In wasm backend, we need to call the emscripten_asm_const_* functions with
30 // the C vararg calling convention, because we will call it with a variety of
31 // arguments, but need to generate a coherent import for the wasm module before
32 // binaryen can run over it to fix up any calls to emscripten_asm_const_*.  In
33 // order to read from a vararg buffer, we need to know the signatures to read.
34 // We can use compile-time trickery to generate a format string, and read that
35 // in JS in order to correctly handle the vararg buffer.
36 
37 #ifndef __cplusplus
38 
39 // We can use the generic selection C11 feature (that clang supports pre-C11
40 // as an extension) to emulate function overloading in C.
41 // All pointer types should go through the default case.
42 #define _EM_ASM_SIG_CHAR(x) _Generic((x), \
43     float: 'f', \
44     double: 'd', \
45     int: 'i', \
46     unsigned: 'i', \
47     default: 'i')
48 
49 // This indirection is needed to allow us to concatenate computed results, e.g.
50 //   #define BAR(N) _EM_ASM_CONCATENATE(FOO_, N)
51 //   BAR(3) // rewritten to BAR_3
52 // whereas using ## or _EM_ASM_CONCATENATE_ directly would result in BAR_N
53 #define _EM_ASM_CONCATENATE(a, b) _EM_ASM_CONCATENATE_(a, b)
54 #define _EM_ASM_CONCATENATE_(a, b) a##b
55 
56 // Counts arguments. We use $$ as a sentinel value to enable using ##__VA_ARGS__
57 // which omits a comma in the event that we have 0 arguments passed, which is
58 // necessary to keep the count correct.
59 #define _EM_ASM_COUNT_ARGS_EXP(_$,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,n,...) n
60 #define _EM_ASM_COUNT_ARGS(...) \
61     _EM_ASM_COUNT_ARGS_EXP($$,##__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
62 
63 // Find the corresponding char for each argument.
64 #define _EM_ASM_ARG_SIGS_0(x, ...)
65 #define _EM_ASM_ARG_SIGS_1(x, ...) _EM_ASM_SIG_CHAR(x),
66 #define _EM_ASM_ARG_SIGS_2(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_1(__VA_ARGS__)
67 #define _EM_ASM_ARG_SIGS_3(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_2(__VA_ARGS__)
68 #define _EM_ASM_ARG_SIGS_4(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_3(__VA_ARGS__)
69 #define _EM_ASM_ARG_SIGS_5(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_4(__VA_ARGS__)
70 #define _EM_ASM_ARG_SIGS_6(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_5(__VA_ARGS__)
71 #define _EM_ASM_ARG_SIGS_7(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_6(__VA_ARGS__)
72 #define _EM_ASM_ARG_SIGS_8(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_7(__VA_ARGS__)
73 #define _EM_ASM_ARG_SIGS_9(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_8(__VA_ARGS__)
74 #define _EM_ASM_ARG_SIGS_10(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_9(__VA_ARGS__)
75 #define _EM_ASM_ARG_SIGS_11(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_10(__VA_ARGS__)
76 #define _EM_ASM_ARG_SIGS_12(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_11(__VA_ARGS__)
77 #define _EM_ASM_ARG_SIGS_13(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_12(__VA_ARGS__)
78 #define _EM_ASM_ARG_SIGS_14(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_13(__VA_ARGS__)
79 #define _EM_ASM_ARG_SIGS_15(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_14(__VA_ARGS__)
80 #define _EM_ASM_ARG_SIGS_16(x, ...) _EM_ASM_SIG_CHAR(x), _EM_ASM_ARG_SIGS_15(__VA_ARGS__)
81 #define _EM_ASM_ARG_SIGS_(N, ...) \
82     ((char[]){ _EM_ASM_CONCATENATE(_EM_ASM_ARG_SIGS_,N)(__VA_ARGS__) '\0' })
83 
84 #define _EM_ASM_ARG_SIGS(...) \
85     _EM_ASM_ARG_SIGS_(_EM_ASM_COUNT_ARGS(__VA_ARGS__), ##__VA_ARGS__)
86 
87 // We lead with commas to avoid adding an extra comma in the 0-argument case.
88 #define _EM_ASM_PREP_ARGS(...) , _EM_ASM_ARG_SIGS(__VA_ARGS__), ##__VA_ARGS__
89 
90 #else // __cplusplus
91 
92 // C++ needs to support vararg template parameter packs, e.g. like in
93 // tests/core/test_em_asm_parameter_pack.cpp. Because of that, a macro-only
94 // approach doesn't work (a macro applied to a parameter pack would expand
95 // incorrectly). So we can use a template class instead to build a temporary
96 // buffer of characters.
97 
98 // As emscripten is require to build successfully with -std=c++03, we cannot
99 // use std::tuple or std::integral_constant. Using C++11 features is only a
100 // warning in modern Clang, which are ignored in system headers.
101 template<typename, typename = void> struct __em_asm_sig {};
102 template<> struct __em_asm_sig<float> { static const char value = 'd'; };
103 template<> struct __em_asm_sig<double> { static const char value = 'd'; };
104 template<> struct __em_asm_sig<char> { static const char value = 'i'; };
105 template<> struct __em_asm_sig<signed char> { static const char value = 'i'; };
106 template<> struct __em_asm_sig<unsigned char> { static const char value = 'i'; };
107 template<> struct __em_asm_sig<short> { static const char value = 'i'; };
108 template<> struct __em_asm_sig<unsigned short> { static const char value = 'i'; };
109 template<> struct __em_asm_sig<int> { static const char value = 'i'; };
110 template<> struct __em_asm_sig<unsigned int> { static const char value = 'i'; };
111 template<> struct __em_asm_sig<long> { static const char value = 'i'; };
112 template<> struct __em_asm_sig<unsigned long> { static const char value = 'i'; };
113 template<> struct __em_asm_sig<bool> { static const char value = 'i'; };
114 template<> struct __em_asm_sig<wchar_t> { static const char value = 'i'; };
115 template<typename T> struct __em_asm_sig<T*> { static const char value = 'i'; };
116 
117 // Explicit support for enums, they're passed as int via variadic arguments.
118 template<bool> struct __em_asm_if { };
119 template<> struct __em_asm_if<true> { typedef void type; };
120 template<typename T> struct __em_asm_sig<T, typename __em_asm_if<__is_enum(T)>::type> {
121     static const char value = 'i';
122 };
123 
124 // Instead of std::tuple
125 template<typename... Args>
126 struct __em_asm_type_tuple {};
127 
128 // Instead of std::make_tuple
129 template<typename... Args>
130 __em_asm_type_tuple<Args...> __em_asm_make_type_tuple(Args... args) {
131     return {};
132 }
133 
134 template<typename>
135 struct __em_asm_sig_builder {};
136 
137 template<typename... Args>
138 struct __em_asm_sig_builder<__em_asm_type_tuple<Args...> > {
139   static const char buffer[sizeof...(Args) + 1];
140 };
141 
142 template<typename... Args>
143 const char __em_asm_sig_builder<__em_asm_type_tuple<Args...> >::buffer[] = { __em_asm_sig<Args>::value..., 0 };
144 
145 // We move to type level with decltype(make_tuple(...)) to avoid double
146 // evaluation of arguments. Use __typeof__ instead of decltype, though,
147 // because the header should be able to compile with clang's -std=c++03.
148 #define _EM_ASM_PREP_ARGS(...) \
149     , __em_asm_sig_builder<__typeof__(__em_asm_make_type_tuple(__VA_ARGS__))>::buffer, ##__VA_ARGS__
150 
151 extern "C" {
152 #endif // __cplusplus
153 
154 // C++ needs the nothrow attribute so -O0 doesn't lower these calls as invokes.
155 __attribute__((nothrow))
156 int emscripten_asm_const_int(const char* code, const char* arg_sigs, ...);
157 __attribute__((nothrow))
158 double emscripten_asm_const_double(const char* code, const char* arg_sigs, ...);
159 
160 __attribute__((nothrow))
161 int emscripten_asm_const_int_sync_on_main_thread(
162   const char* code, const char* arg_sigs, ...);
163 __attribute__((nothrow))
164 double emscripten_asm_const_double_sync_on_main_thread(
165   const char* code, const char* arg_sigs, ...);
166 
167 __attribute__((nothrow))
168 void emscripten_asm_const_async_on_main_thread(
169   const char* code, const char* arg_sigs, ...);
170 
171 #ifdef __cplusplus
172 }
173 #endif // __cplusplus
174 
175 #else // __asmjs__
176 
177 #ifdef __cplusplus
178 extern "C" {
179 #endif // __cplusplus
180 
181 #define _EM_ASM_PREP_ARGS(...) , ##__VA_ARGS__
182 
183 int emscripten_asm_const_int(const char* code, ...);
184 double emscripten_asm_const_double(const char* code, ...);
185 
186 int emscripten_asm_const_int_sync_on_main_thread(const char* code, ...);
187 double emscripten_asm_const_double_sync_on_main_thread(const char* code, ...);
188 
189 void emscripten_asm_const_async_on_main_thread(const char* code, ...);
190 
191 #ifdef __cplusplus
192 }
193 #endif // __cplusplus
194 
195 #endif // __asmjs__
196 
197 // Note: If the code block in the EM_ASM() family of functions below contains a comma,
198 // then wrap the whole code block inside parentheses (). See tests/core/test_em_asm_2.cpp
199 // for example code snippets.
200 
201 // Runs the given JavaScript code on the calling thread (synchronously), and returns no value back.
202 #define EM_ASM(code, ...) ((void)emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)))
203 
204 // Runs the given JavaScript code on the calling thread (synchronously), and returns an integer back.
205 #define EM_ASM_INT(code, ...) emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))
206 
207 // Runs the given JavaScript code on the calling thread (synchronously), and returns a double back.
208 #define EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))
209 
210 // Runs the given JavaScript code synchronously on the main browser thread, and returns no value back.
211 // Call this function for example to access DOM elements in a pthread when building with -s USE_PTHREADS=1.
212 // Avoid calling this function in performance sensitive code, because this will effectively sleep the
213 // calling thread until the main browser thread is able to service the proxied function call. If you have
214 // multiple MAIN_THREAD_EM_ASM() code blocks to call in succession, it will likely be much faster to
215 // coalesce all the calls to a single MAIN_THREAD_EM_ASM() block. If you do not need synchronization nor
216 // a return value back, consider using the function MAIN_THREAD_ASYNC_EM_ASM() instead, which will not block.
217 // In single-threaded builds (including proxy-to-worker), MAIN_THREAD_EM_ASM*()
218 // functions are direct aliases to the corresponding EM_ASM*() family of functions.
219 #define MAIN_THREAD_EM_ASM(code, ...) ((void)emscripten_asm_const_int_sync_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)))
220 
221 // Runs the given JavaScript code synchronously on the main browser thread, and returns an integer back.
222 // The same considerations apply as with MAIN_THREAD_EM_ASM().
223 #define MAIN_THREAD_EM_ASM_INT(code, ...) emscripten_asm_const_int_sync_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))
224 
225 // Runs the given JavaScript code synchronously on the main browser thread, and returns a double back.
226 // The same considerations apply as with MAIN_THREAD_EM_ASM().
227 #define MAIN_THREAD_EM_ASM_DOUBLE(code, ...) emscripten_asm_const_double_sync_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))
228 
229 // Asynchronously dispatches the given JavaScript code to be run on the main browser thread.
230 // If the calling thread is the main browser thread, then the specified JavaScript code is executed
231 // synchronously. Otherwise an event will be queued on the main browser thread to execute the call
232 // later (think postMessage()), and this call will immediately return without waiting. Be sure to
233 // guard any accesses to shared memory on the heap inside the JavaScript code with appropriate locking.
234 #define MAIN_THREAD_ASYNC_EM_ASM(code, ...) ((void)emscripten_asm_const_async_on_main_thread(#code _EM_ASM_PREP_ARGS(__VA_ARGS__)))
235 
236 // Old forms for compatibility, no need to use these.
237 // Replace EM_ASM_, EM_ASM_ARGS and EM_ASM_INT_V with EM_ASM_INT,
238 // and EM_ASM_DOUBLE_V with EM_ASM_DOUBLE.
239 #define EM_ASM_(code, ...) emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))
240 #define EM_ASM_ARGS(code, ...) emscripten_asm_const_int(#code _EM_ASM_PREP_ARGS(__VA_ARGS__))
241 #define EM_ASM_INT_V(code) EM_ASM_INT(#code)
242 #define EM_ASM_DOUBLE_V(code) EM_ASM_DOUBLE(#code)
243 
244 #endif // !defined(__cplusplus) && defined(__STRICT_ANSI__)
245