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