1 /* 2 * Copyright 2012 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 #if __cplusplus < 201103L 11 #error Including <emscripten/val.h> requires building with -std=c++11 or newer! 12 #endif 13 14 #include <stdint.h> // uintptr_t 15 #include <emscripten/wire.h> 16 #include <array> 17 #include <vector> 18 19 20 namespace emscripten { 21 22 class val; 23 24 namespace internal { 25 26 template<typename WrapperType> 27 val wrapped_extend(const std::string&, const val&); 28 29 // Implemented in JavaScript. Don't call these directly. 30 extern "C" { 31 void _emval_register_symbol(const char*); 32 33 enum { 34 _EMVAL_UNDEFINED = 1, 35 _EMVAL_NULL = 2, 36 _EMVAL_TRUE = 3, 37 _EMVAL_FALSE = 4 38 }; 39 40 typedef struct _EM_VAL* EM_VAL; 41 typedef struct _EM_DESTRUCTORS* EM_DESTRUCTORS; 42 typedef struct _EM_METHOD_CALLER* EM_METHOD_CALLER; 43 typedef double EM_GENERIC_WIRE_TYPE; 44 typedef const void* EM_VAR_ARGS; 45 46 void _emval_incref(EM_VAL value); 47 void _emval_decref(EM_VAL value); 48 49 void _emval_run_destructors(EM_DESTRUCTORS handle); 50 51 EM_VAL _emval_new_array(); 52 EM_VAL _emval_new_object(); 53 EM_VAL _emval_new_cstring(const char*); 54 55 EM_VAL _emval_take_value(TYPEID type, EM_VAR_ARGS argv); 56 57 EM_VAL _emval_new( 58 EM_VAL value, 59 unsigned argCount, 60 const TYPEID argTypes[], 61 EM_VAR_ARGS argv); 62 63 EM_VAL _emval_get_global(const char* name); 64 EM_VAL _emval_get_module_property(const char* name); 65 EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); 66 void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); 67 EM_GENERIC_WIRE_TYPE _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* destructors); 68 69 bool _emval_equals(EM_VAL first, EM_VAL second); 70 bool _emval_strictly_equals(EM_VAL first, EM_VAL second); 71 bool _emval_greater_than(EM_VAL first, EM_VAL second); 72 bool _emval_less_than(EM_VAL first, EM_VAL second); 73 bool _emval_not(EM_VAL object); 74 75 EM_VAL _emval_call( 76 EM_VAL value, 77 unsigned argCount, 78 const TYPEID argTypes[], 79 EM_VAR_ARGS argv); 80 81 // DO NOT call this more than once per signature. It will 82 // leak generated function objects! 83 EM_METHOD_CALLER _emval_get_method_caller( 84 unsigned argCount, // including return value 85 const TYPEID argTypes[]); 86 EM_GENERIC_WIRE_TYPE _emval_call_method( 87 EM_METHOD_CALLER caller, 88 EM_VAL handle, 89 const char* methodName, 90 EM_DESTRUCTORS* destructors, 91 EM_VAR_ARGS argv); 92 void _emval_call_void_method( 93 EM_METHOD_CALLER caller, 94 EM_VAL handle, 95 const char* methodName, 96 EM_VAR_ARGS argv); 97 EM_VAL _emval_typeof(EM_VAL value); 98 bool _emval_instanceof(EM_VAL object, EM_VAL constructor); 99 bool _emval_is_number(EM_VAL object); 100 bool _emval_is_string(EM_VAL object); 101 bool _emval_in(EM_VAL item, EM_VAL object); 102 bool _emval_delete(EM_VAL object, EM_VAL property); 103 bool _emval_throw(EM_VAL object); 104 EM_VAL _emval_await(EM_VAL promise); 105 } 106 107 template<const char* address> 108 struct symbol_registrar { symbol_registrarsymbol_registrar109 symbol_registrar() { 110 internal::_emval_register_symbol(address); 111 } 112 }; 113 114 template<typename ReturnType, typename... Args> 115 struct Signature { 116 /* 117 typedef typename BindingType<ReturnType>::WireType (*MethodCaller)( 118 EM_VAL value, 119 const char* methodName, 120 EM_DESTRUCTORS* destructors, 121 typename BindingType<Args>::WireType...); 122 */ 123 get_method_callerSignature124 static EM_METHOD_CALLER get_method_caller() { 125 static EM_METHOD_CALLER mc = init_method_caller(); 126 return mc; 127 } 128 129 private: init_method_callerSignature130 static EM_METHOD_CALLER init_method_caller() { 131 WithPolicies<>::ArgTypeList<ReturnType, Args...> args; 132 return _emval_get_method_caller(args.getCount(), args.getTypes()); 133 } 134 }; 135 136 struct DestructorsRunner { 137 public: DestructorsRunnerDestructorsRunner138 explicit DestructorsRunner(EM_DESTRUCTORS d) 139 : destructors(d) 140 {} ~DestructorsRunnerDestructorsRunner141 ~DestructorsRunner() { 142 _emval_run_destructors(destructors); 143 } 144 145 DestructorsRunner(const DestructorsRunner&) = delete; 146 void operator=(const DestructorsRunner&) = delete; 147 148 private: 149 EM_DESTRUCTORS destructors; 150 }; 151 152 template<typename WireType> 153 struct GenericWireTypeConverter { fromGenericWireTypeConverter154 static WireType from(double wt) { 155 return static_cast<WireType>(wt); 156 } 157 }; 158 159 template<typename Pointee> 160 struct GenericWireTypeConverter<Pointee*> { 161 static Pointee* from(double wt) { 162 return reinterpret_cast<Pointee*>(static_cast<uintptr_t>(wt)); 163 } 164 }; 165 166 template<typename T> 167 T fromGenericWireType(double g) { 168 typedef typename BindingType<T>::WireType WireType; 169 WireType wt = GenericWireTypeConverter<WireType>::from(g); 170 return BindingType<T>::fromWireType(wt); 171 } 172 173 template<typename... Args> 174 struct PackSize; 175 176 template<> 177 struct PackSize<> { 178 static constexpr size_t value = 0; 179 }; 180 181 template<typename Arg, typename... Args> 182 struct PackSize<Arg, Args...> { 183 static constexpr size_t value = (sizeof(typename BindingType<Arg>::WireType) + 7) / 8 + PackSize<Args...>::value; 184 }; 185 186 union GenericWireType { 187 union { 188 unsigned u; 189 float f; 190 const void* p; 191 } w[2]; 192 double d; 193 }; 194 static_assert(sizeof(GenericWireType) == 8, "GenericWireType must be 8 bytes"); 195 static_assert(alignof(GenericWireType) == 8, "GenericWireType must be 8-byte-aligned"); 196 197 inline void writeGenericWireType(GenericWireType*& cursor, float wt) { 198 cursor->w[0].f = wt; 199 ++cursor; 200 } 201 202 inline void writeGenericWireType(GenericWireType*& cursor, double wt) { 203 cursor->d = wt; 204 ++cursor; 205 } 206 207 template<typename T> 208 void writeGenericWireType(GenericWireType*& cursor, T* wt) { 209 cursor->w[0].p = wt; 210 ++cursor; 211 } 212 213 template<typename ElementType> 214 inline void writeGenericWireType(GenericWireType*& cursor, const memory_view<ElementType>& wt) { 215 cursor->w[0].u = wt.size; 216 cursor->w[1].p = wt.data; 217 ++cursor; 218 } 219 220 template<typename T> 221 void writeGenericWireType(GenericWireType*& cursor, T wt) { 222 cursor->w[0].u = static_cast<unsigned>(wt); 223 ++cursor; 224 } 225 226 inline void writeGenericWireTypes(GenericWireType*&) { 227 } 228 229 template<typename First, typename... Rest> 230 EMSCRIPTEN_ALWAYS_INLINE void writeGenericWireTypes(GenericWireType*& cursor, First&& first, Rest&&... rest) { 231 writeGenericWireType(cursor, BindingType<First>::toWireType(std::forward<First>(first))); 232 writeGenericWireTypes(cursor, std::forward<Rest>(rest)...); 233 } 234 235 template<typename... Args> 236 struct WireTypePack { 237 WireTypePack(Args&&... args) { 238 GenericWireType* cursor = elements.data(); 239 writeGenericWireTypes(cursor, std::forward<Args>(args)...); 240 } 241 242 operator EM_VAR_ARGS() const { 243 return elements.data(); 244 } 245 246 private: 247 std::array<GenericWireType, PackSize<Args...>::value> elements; 248 }; 249 250 template<typename ReturnType, typename... Args> 251 struct MethodCaller { 252 static ReturnType call(EM_VAL handle, const char* methodName, Args&&... args) { 253 auto caller = Signature<ReturnType, Args...>::get_method_caller(); 254 255 WireTypePack<Args...> argv(std::forward<Args>(args)...); 256 EM_DESTRUCTORS destructors; 257 EM_GENERIC_WIRE_TYPE result = _emval_call_method( 258 caller, 259 handle, 260 methodName, 261 &destructors, 262 argv); 263 DestructorsRunner rd(destructors); 264 return fromGenericWireType<ReturnType>(result); 265 } 266 }; 267 268 template<typename... Args> 269 struct MethodCaller<void, Args...> { 270 static void call(EM_VAL handle, const char* methodName, Args&&... args) { 271 auto caller = Signature<void, Args...>::get_method_caller(); 272 273 WireTypePack<Args...> argv(std::forward<Args>(args)...); 274 _emval_call_void_method( 275 caller, 276 handle, 277 methodName, 278 argv); 279 } 280 }; 281 } 282 283 #define EMSCRIPTEN_SYMBOL(name) \ 284 static const char name##_symbol[] = #name; \ 285 static const ::emscripten::internal::symbol_registrar<name##_symbol> name##_registrar 286 287 class val { 288 public: 289 // missing operators: 290 // * ~ - + ++ -- 291 // * * / % 292 // * + - 293 // * << >> >>> 294 // * & ^ | && || ?: 295 // 296 // exposing void, comma, and conditional is unnecessary 297 // same with: = += -= *= /= %= <<= >>= >>>= &= ^= |= 298 299 static val array() { 300 return val(internal::_emval_new_array()); 301 } 302 303 template<typename Iter> 304 static val array(Iter begin, Iter end) { 305 val new_array = array(); 306 for (auto it = begin; it != end; ++it) { 307 new_array.call<void>("push", *it); 308 } 309 return new_array; 310 } 311 312 template<typename T> 313 static val array(const std::vector<T>& vec) { 314 return array(vec.begin(), vec.end()); 315 } 316 317 static val object() { 318 return val(internal::_emval_new_object()); 319 } 320 321 static val undefined() { 322 return val(internal::EM_VAL(internal::_EMVAL_UNDEFINED)); 323 } 324 325 static val null() { 326 return val(internal::EM_VAL(internal::_EMVAL_NULL)); 327 } 328 329 static val take_ownership(internal::EM_VAL e) { 330 return val(e); 331 } 332 333 static val global(const char* name = 0) { 334 return val(internal::_emval_get_global(name)); 335 } 336 337 static val module_property(const char* name) { 338 return val(internal::_emval_get_module_property(name)); 339 } 340 341 template<typename T> 342 explicit val(T&& value) { 343 using namespace internal; 344 345 typedef internal::BindingType<T> BT; 346 WireTypePack<T> argv(std::forward<T>(value)); 347 handle = _emval_take_value( 348 internal::TypeID<T>::get(), 349 argv); 350 } 351 352 val() = delete; 353 354 explicit val(const char* v) 355 : handle(internal::_emval_new_cstring(v)) 356 {} 357 358 val(val&& v) 359 : handle(v.handle) 360 { 361 v.handle = 0; 362 } 363 364 val(const val& v) 365 : handle(v.handle) 366 { 367 internal::_emval_incref(handle); 368 } 369 370 ~val() { 371 internal::_emval_decref(handle); 372 } 373 374 val& operator=(val&& v) { 375 internal::_emval_decref(handle); 376 handle = v.handle; 377 v.handle = 0; 378 return *this; 379 } 380 381 val& operator=(const val& v) { 382 internal::_emval_incref(v.handle); 383 internal::_emval_decref(handle); 384 handle = v.handle; 385 return *this; 386 } 387 388 bool hasOwnProperty(const char* key) const { 389 return val::global("Object")["prototype"]["hasOwnProperty"].call<bool>("call", *this, val(key)); 390 } 391 392 bool isNull() const { 393 return handle == internal::EM_VAL(internal::_EMVAL_NULL); 394 } 395 396 bool isUndefined() const { 397 return handle == internal::EM_VAL(internal::_EMVAL_UNDEFINED); 398 } 399 400 bool isTrue() const { 401 return handle == internal::EM_VAL(internal::_EMVAL_TRUE); 402 } 403 404 bool isFalse() const { 405 return handle == internal::EM_VAL(internal::_EMVAL_FALSE); 406 } 407 408 bool isNumber() const { 409 return internal::_emval_is_number(handle); 410 } 411 412 bool isString() const { 413 return internal::_emval_is_string(handle); 414 } 415 416 bool isArray() const { 417 return instanceof(global("Array")); 418 } 419 420 bool equals(const val& v) const { 421 return internal::_emval_equals(handle, v.handle); 422 } 423 424 bool operator==(const val& v) const { 425 return internal::_emval_equals(handle, v.handle); 426 } 427 428 bool operator!=(const val& v) const { 429 return !(*this == v); 430 } 431 432 bool strictlyEquals(const val& v) const { 433 return internal::_emval_strictly_equals(handle, v.handle); 434 } 435 436 bool operator>(const val& v) const { 437 return internal::_emval_greater_than(handle, v.handle); 438 } 439 440 bool operator>=(const val& v) const { 441 return (*this > v) || (*this == v); 442 } 443 444 bool operator<(const val& v) const { 445 return internal::_emval_less_than(handle, v.handle); 446 } 447 448 bool operator<=(const val& v) const { 449 return (*this < v) || (*this == v); 450 } 451 452 bool operator!() const { 453 return internal::_emval_not(handle); 454 } 455 456 template<typename... Args> 457 val new_(Args&&... args) const { 458 return internalCall(internal::_emval_new,std::forward<Args>(args)...); 459 } 460 461 template<typename T> 462 val operator[](const T& key) const { 463 return val(internal::_emval_get_property(handle, val(key).handle)); 464 } 465 466 template<typename K> 467 void set(const K& key, const val& v) { 468 internal::_emval_set_property(handle, val(key).handle, v.handle); 469 } 470 471 template<typename K, typename V> 472 void set(const K& key, const V& value) { 473 internal::_emval_set_property(handle, val(key).handle, val(value).handle); 474 } 475 476 template<typename... Args> 477 val operator()(Args&&... args) const { 478 return internalCall(internal::_emval_call, std::forward<Args>(args)...); 479 } 480 481 template<typename ReturnValue, typename... Args> 482 ReturnValue call(const char* name, Args&&... args) const { 483 using namespace internal; 484 485 return MethodCaller<ReturnValue, Args...>::call(handle, name, std::forward<Args>(args)...); 486 } 487 488 template<typename T, typename ...Policies> 489 T as(Policies...) const { 490 using namespace internal; 491 492 typedef BindingType<T> BT; 493 typename WithPolicies<Policies...>::template ArgTypeList<T> targetType; 494 495 EM_DESTRUCTORS destructors; 496 EM_GENERIC_WIRE_TYPE result = _emval_as( 497 handle, 498 targetType.getTypes()[0], 499 &destructors); 500 DestructorsRunner dr(destructors); 501 return fromGenericWireType<T>(result); 502 } 503 504 // If code is not being compiled with GNU extensions enabled, typeof() is not a reserved keyword, so support that as a member function. 505 #if __STRICT_ANSI__ 506 val typeof() const { 507 return val(_emval_typeof(handle)); 508 } 509 #endif 510 511 // Prefer calling val::typeOf() over val::typeof(), since this form works in both C++11 and GNU++11 build modes. "typeof" is a reserved word in GNU++11 extensions. 512 val typeOf() const { 513 return val(_emval_typeof(handle)); 514 } 515 516 bool instanceof(const val& v) const { 517 return internal::_emval_instanceof(handle, v.handle); 518 } 519 520 bool in(const val& v) const { 521 return internal::_emval_in(handle, v.handle); 522 } 523 524 template<typename T> 525 bool delete_(const T& property) const { 526 return internal::_emval_delete(handle, val(property).handle); 527 } 528 529 void throw_() const { 530 internal::_emval_throw(handle); 531 } 532 533 val await() const { 534 return val(internal::_emval_await(handle)); 535 } 536 537 private: 538 // takes ownership, assumes handle already incref'd 539 explicit val(internal::EM_VAL handle) 540 : handle(handle) 541 {} 542 543 template<typename WrapperType> 544 friend val internal::wrapped_extend(const std::string& , const val& ); 545 546 internal::EM_VAL __get_handle() const { 547 return handle; 548 } 549 550 template<typename Implementation, typename... Args> 551 val internalCall(Implementation impl, Args&&... args) const { 552 using namespace internal; 553 554 WithPolicies<>::ArgTypeList<Args...> argList; 555 WireTypePack<Args...> argv(std::forward<Args>(args)...); 556 return val( 557 impl( 558 handle, 559 argList.getCount(), 560 argList.getTypes(), 561 argv)); 562 } 563 564 internal::EM_VAL handle; 565 566 friend struct internal::BindingType<val>; 567 }; 568 569 namespace internal { 570 template<> 571 struct BindingType<val> { 572 typedef internal::EM_VAL WireType; 573 static WireType toWireType(const val& v) { 574 _emval_incref(v.handle); 575 return v.handle; 576 } 577 static val fromWireType(WireType v) { 578 return val::take_ownership(v); 579 } 580 }; 581 } 582 583 template<typename T> 584 std::vector<T> vecFromJSArray(val v) { 585 auto l = v["length"].as<unsigned>(); 586 587 std::vector<T> rv; 588 for(unsigned i = 0; i < l; ++i) { 589 rv.push_back(v[i].as<T>()); 590 } 591 592 return rv; 593 }; 594 } 595