1 // Wasmtime-vendored copy of this header file as present in upstream: 2 // <https://github.com/WebAssembly/wasm-c-api/blob/9d6b93764ac96cdd9db51081c363e09d2d488b4d/include/wasm.hh> 3 // 4 // Wasmtime maintainers can update this vendored copy in-tree with the 5 // ./ci/vendor-c-api-headers.sh shell script. 6 // 7 // WebAssembly C++ API 8 9 #ifndef WASM_HH 10 #define WASM_HH 11 12 #include <cassert> 13 #include <cstddef> 14 #include <cstdint> 15 #include <cstring> 16 #include <memory> 17 #include <new> 18 #include <limits> 19 #include <string> 20 21 #ifndef WASM_API_EXTERN 22 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(LIBWASM_STATIC) 23 #define WASM_API_EXTERN __declspec(dllimport) 24 #else 25 #define WASM_API_EXTERN 26 #endif 27 #endif 28 29 30 /////////////////////////////////////////////////////////////////////////////// 31 // Auxiliaries 32 33 // Machine types 34 35 static_assert(sizeof(float) == sizeof(int32_t), "incompatible float type"); 36 static_assert(sizeof(double) == sizeof(int64_t), "incompatible double type"); 37 static_assert(sizeof(intptr_t) == sizeof(int32_t) || 38 sizeof(intptr_t) == sizeof(int64_t), "incompatible pointer type"); 39 40 using byte_t = char; 41 using float32_t = float; 42 using float64_t = double; 43 44 45 namespace wasm { 46 47 // Vectors 48 49 template<class T> 50 class vec { 51 static const size_t invalid_size = SIZE_MAX; 52 53 size_t size_; 54 std::unique_ptr<T[]> data_; 55 56 #ifdef WASM_API_DEBUG 57 WASM_API_EXTERN void make_data(); 58 WASM_API_EXTERN void free_data(); 59 #else 60 void make_data() {} 61 void free_data() {} 62 #endif 63 64 vec(size_t size) : vec(size, size ? new(std::nothrow) T[size] : nullptr) { 65 make_data(); 66 } 67 68 vec(size_t size, T* data) : size_(size), data_(data) { 69 assert(!!size_ == !!data_ || size_ == invalid_size); 70 } 71 72 public: 73 using elem_type = T; 74 75 vec(vec<T>&& that) : vec(that.size_, that.data_.release()) { 76 that.size_ = invalid_size; 77 } 78 79 ~vec() { 80 free_data(); 81 } 82 83 operator bool() const { 84 return bool(size_ != invalid_size); 85 } 86 87 auto size() const -> size_t { 88 return size_; 89 } 90 91 auto get() const -> const T* { 92 return data_.get(); 93 } 94 95 auto get() -> T* { 96 return data_.get(); 97 } 98 99 auto release() -> T* { 100 size_ = invalid_size; 101 return data_.release(); 102 } 103 104 void reset() { 105 free_data(); 106 size_ = invalid_size; 107 data_.reset(); 108 } 109 110 void reset(vec& that) { 111 free_data(); 112 size_ = that.size_; 113 data_.reset(that.data_.release()); 114 that.size_ = invalid_size; 115 } 116 117 auto operator=(vec&& that) -> vec& { 118 reset(that); 119 return *this; 120 } 121 122 auto operator[](size_t i) -> T& { 123 assert(i < size_); 124 return data_[i]; 125 } 126 127 auto operator[](size_t i) const -> const T& { 128 assert(i < size_); 129 return data_[i]; 130 } 131 132 auto copy() const -> vec { 133 auto v = vec(size_); 134 if (v) for (size_t i = 0; i < size_; ++i) v.data_[i] = data_[i]; 135 return v; 136 } 137 138 // TODO: This can't be used for e.g. vec<Val> 139 auto deep_copy() const -> vec { 140 auto v = vec(size_); 141 if (v) for (size_t i = 0; i < size_; ++i) v.data_[i] = data_[i]->copy(); 142 return v; 143 } 144 145 static auto make_uninitialized(size_t size = 0) -> vec { 146 return vec(size); 147 } 148 149 static auto make(size_t size, T init[]) -> vec { 150 auto v = vec(size); 151 if (v) for (size_t i = 0; i < size; ++i) v.data_[i] = std::move(init[i]); 152 return v; 153 } 154 155 static auto make(std::string s) -> vec<char> { 156 auto v = vec(s.length()); 157 if (v) std::strncpy(v.get(), s.data(), s.length()); 158 return v; 159 } 160 161 static auto make_nt(std::string s) -> vec<char> { 162 auto v = vec(s.length() + 1); 163 if (v) std::strcpy(v.get(), s.data()); 164 return v; 165 } 166 167 // TODO(mvsc): MVSC requires this special case: 168 static auto make() -> vec { 169 return vec(0); 170 } 171 172 template<class... Ts> 173 static auto make(Ts&&... args) -> vec { 174 T data[] = { std::forward<Ts>(args)... }; 175 return make(sizeof...(Ts), data); 176 } 177 178 static auto adopt(size_t size, T data[]) -> vec { 179 return vec(size, data); 180 } 181 182 static auto invalid() -> vec { 183 return vec(invalid_size, nullptr); 184 } 185 }; 186 187 188 // Ownership 189 190 class destroyer { 191 public: 192 template <typename T> 193 void operator()(T* ptr) { 194 ptr->destroy(); 195 } 196 }; 197 198 template<class T> using own = std::unique_ptr<T, destroyer>; 199 template<class T> using ownvec = vec<own<T>>; 200 201 template<class T> own<T> make_own(T* ptr) { 202 return own<T>(ptr); 203 } 204 205 /////////////////////////////////////////////////////////////////////////////// 206 // Runtime Environment 207 208 // Configuration 209 210 class WASM_API_EXTERN Config { 211 friend class destroyer; 212 void destroy(); 213 214 protected: 215 Config() = default; 216 ~Config() = default; 217 218 public: 219 static auto make() -> own<Config>; 220 221 // Implementations may provide custom methods for manipulating Configs. 222 }; 223 224 225 // Engine 226 227 class WASM_API_EXTERN Engine { 228 friend class destroyer; 229 void destroy(); 230 231 protected: 232 Engine() = default; 233 ~Engine() = default; 234 235 public: 236 static auto make(own<Config>&& = Config::make()) -> own<Engine>; 237 }; 238 239 240 // Store 241 242 class WASM_API_EXTERN Store { 243 friend class destroyer; 244 void destroy(); 245 246 protected: 247 Store() = default; 248 ~Store() = default; 249 250 public: 251 static auto make(Engine*) -> own<Store>; 252 }; 253 254 255 /////////////////////////////////////////////////////////////////////////////// 256 // Type Representations 257 258 // Type attributes 259 260 enum class Mutability : uint8_t { CONST, VAR }; 261 262 struct Limits { 263 uint32_t min; 264 uint32_t max; 265 266 Limits(uint32_t min, uint32_t max = std::numeric_limits<uint32_t>::max()) : 267 min(min), max(max) {} 268 }; 269 270 271 // Value Types 272 273 enum class ValKind : uint8_t { 274 I32, I64, F32, F64, 275 EXTERNREF = 128, FUNCREF, 276 }; 277 278 inline bool is_num(ValKind k) { return k < ValKind::EXTERNREF; } 279 inline bool is_ref(ValKind k) { return k >= ValKind::EXTERNREF; } 280 281 282 class WASM_API_EXTERN ValType { 283 friend class destroyer; 284 void destroy(); 285 286 protected: 287 ValType() = default; 288 ~ValType() = default; 289 290 public: 291 static auto make(ValKind) -> own<ValType>; 292 auto copy() const -> own<ValType>; 293 294 auto kind() const -> ValKind; 295 auto is_num() const -> bool { return wasm::is_num(kind()); } 296 auto is_ref() const -> bool { return wasm::is_ref(kind()); } 297 }; 298 299 300 // External Types 301 302 enum class ExternKind : uint8_t { 303 FUNC, GLOBAL, TABLE, MEMORY, TAG 304 }; 305 306 class FuncType; 307 class GlobalType; 308 class TableType; 309 class MemoryType; 310 class TagType; 311 312 class WASM_API_EXTERN ExternType { 313 friend class destroyer; 314 void destroy(); 315 316 protected: 317 ExternType() = default; 318 ~ExternType() = default; 319 320 public: 321 auto copy() const-> own<ExternType>; 322 323 auto kind() const -> ExternKind; 324 325 auto func() -> FuncType*; 326 auto global() -> GlobalType*; 327 auto table() -> TableType*; 328 auto memory() -> MemoryType*; 329 auto tag() -> TagType*; 330 331 auto func() const -> const FuncType*; 332 auto global() const -> const GlobalType*; 333 auto table() const -> const TableType*; 334 auto memory() const -> const MemoryType*; 335 auto tag() const -> const TagType*; 336 }; 337 338 339 // Function Types 340 341 class WASM_API_EXTERN FuncType : public ExternType { 342 friend class destroyer; 343 void destroy(); 344 345 protected: 346 FuncType() = default; 347 ~FuncType() = default; 348 349 public: 350 static auto make( 351 ownvec<ValType>&& params = ownvec<ValType>::make(), 352 ownvec<ValType>&& results = ownvec<ValType>::make() 353 ) -> own<FuncType>; 354 355 auto copy() const -> own<FuncType>; 356 357 auto params() const -> const ownvec<ValType>&; 358 auto results() const -> const ownvec<ValType>&; 359 }; 360 361 362 // Global Types 363 364 class WASM_API_EXTERN GlobalType : public ExternType { 365 friend class destroyer; 366 void destroy(); 367 368 protected: 369 GlobalType() = default; 370 ~GlobalType() = default; 371 372 public: 373 static auto make(own<ValType>&&, Mutability) -> own<GlobalType>; 374 auto copy() const -> own<GlobalType>; 375 376 auto content() const -> const ValType*; 377 auto mutability() const -> Mutability; 378 }; 379 380 381 // Table Types 382 383 class WASM_API_EXTERN TableType : public ExternType { 384 friend class destroyer; 385 void destroy(); 386 387 protected: 388 TableType() = default; 389 ~TableType() = default; 390 391 public: 392 static auto make(own<ValType>&&, Limits) -> own<TableType>; 393 auto copy() const -> own<TableType>; 394 395 auto element() const -> const ValType*; 396 auto limits() const -> const Limits&; 397 }; 398 399 400 // Memory Types 401 402 class WASM_API_EXTERN MemoryType : public ExternType { 403 friend class destroyer; 404 void destroy(); 405 406 protected: 407 MemoryType() = default; 408 ~MemoryType() = default; 409 410 public: 411 static auto make(Limits) -> own<MemoryType>; 412 auto copy() const -> own<MemoryType>; 413 414 auto limits() const -> const Limits&; 415 }; 416 417 418 // Tag Types 419 420 class WASM_API_EXTERN TagType : public ExternType { 421 friend class destroyer; 422 void destroy(); 423 424 protected: 425 TagType() = default; 426 ~TagType() = default; 427 428 public: 429 static auto make(own<FuncType>&&) -> own<TagType>; 430 auto copy() const -> own<TagType>; 431 432 auto functype() const -> const FuncType*; 433 }; 434 435 436 // Import Types 437 438 using Name = vec<byte_t>; 439 440 class WASM_API_EXTERN ImportType { 441 friend class destroyer; 442 void destroy(); 443 444 protected: 445 ImportType() = default; 446 ~ImportType() = default; 447 448 public: 449 static auto make(Name&& module, Name&& name, own<ExternType>&&) -> 450 own<ImportType>; 451 auto copy() const -> own<ImportType>; 452 453 auto module() const -> const Name&; 454 auto name() const -> const Name&; 455 auto type() const -> const ExternType*; 456 }; 457 458 459 // Export Types 460 461 class WASM_API_EXTERN ExportType { 462 friend class destroyer; 463 void destroy(); 464 465 protected: 466 ExportType() = default; 467 ~ExportType() = default; 468 469 public: 470 static auto make(Name&&, own<ExternType>&&) -> own<ExportType>; 471 auto copy() const -> own<ExportType>; 472 473 auto name() const -> const Name&; 474 auto type() const -> const ExternType*; 475 }; 476 477 478 /////////////////////////////////////////////////////////////////////////////// 479 // Runtime Objects 480 481 // References 482 483 class WASM_API_EXTERN Ref { 484 friend class destroyer; 485 void destroy(); 486 487 protected: 488 Ref() = default; 489 ~Ref() = default; 490 491 public: 492 auto copy() const -> own<Ref>; 493 auto same(const Ref*) const -> bool; 494 495 auto get_host_info() const -> void*; 496 void set_host_info(void* info, void (*finalizer)(void*) = nullptr); 497 }; 498 499 500 // Values 501 502 class Val { 503 ValKind kind_; 504 union impl { 505 int32_t i32; 506 int64_t i64; 507 float32_t f32; 508 float64_t f64; 509 Ref* ref; 510 } impl_; 511 512 Val(ValKind kind, impl impl) : kind_(kind), impl_(impl) {} 513 514 public: 515 Val() : kind_(ValKind::EXTERNREF) { impl_.ref = nullptr; } 516 explicit Val(int32_t i) : kind_(ValKind::I32) { impl_.i32 = i; } 517 explicit Val(int64_t i) : kind_(ValKind::I64) { impl_.i64 = i; } 518 explicit Val(float32_t z) : kind_(ValKind::F32) { impl_.f32 = z; } 519 explicit Val(float64_t z) : kind_(ValKind::F64) { impl_.f64 = z; } 520 explicit Val(own<Ref>&& r) : kind_(ValKind::EXTERNREF) { impl_.ref = r.release(); } 521 522 Val(Val&& that) : kind_(that.kind_), impl_(that.impl_) { 523 if (is_ref()) that.impl_.ref = nullptr; 524 } 525 526 ~Val() { 527 reset(); 528 } 529 530 auto is_num() const -> bool { return wasm::is_num(kind_); } 531 auto is_ref() const -> bool { return wasm::is_ref(kind_); } 532 533 static auto i32(int32_t x) -> Val { return Val(x); } 534 static auto i64(int64_t x) -> Val { return Val(x); } 535 static auto f32(float32_t x) -> Val { return Val(x); } 536 static auto f64(float64_t x) -> Val { return Val(x); } 537 static auto ref(own<Ref>&& x) -> Val { return Val(std::move(x)); } 538 template<class T> inline static auto make(T x) -> Val; 539 template<class T> inline static auto make(own<T>&& x) -> Val; 540 541 void reset() { 542 if (is_ref() && impl_.ref) { 543 destroyer()(impl_.ref); 544 impl_.ref = nullptr; 545 } 546 } 547 548 void reset(Val& that) { 549 reset(); 550 kind_ = that.kind_; 551 impl_ = that.impl_; 552 if (is_ref()) that.impl_.ref = nullptr; 553 } 554 555 auto operator=(Val&& that) -> Val& { 556 reset(that); 557 return *this; 558 } 559 560 auto kind() const -> ValKind { return kind_; } 561 auto i32() const -> int32_t { assert(kind_ == ValKind::I32); return impl_.i32; } 562 auto i64() const -> int64_t { assert(kind_ == ValKind::I64); return impl_.i64; } 563 auto f32() const -> float32_t { assert(kind_ == ValKind::F32); return impl_.f32; } 564 auto f64() const -> float64_t { assert(kind_ == ValKind::F64); return impl_.f64; } 565 auto ref() const -> Ref* { assert(is_ref()); return impl_.ref; } 566 template<class T> inline auto get() const -> T; 567 568 auto release_ref() -> own<Ref> { 569 assert(is_ref()); 570 auto ref = impl_.ref; 571 impl_.ref = nullptr; 572 return own<Ref>(ref); 573 } 574 575 auto copy() const -> Val { 576 if (is_ref() && impl_.ref != nullptr) { 577 // TODO(mvsc): MVSC cannot handle this: 578 // impl impl = {.ref = impl_.ref->copy().release()}; 579 impl impl; 580 impl.ref = impl_.ref->copy().release(); 581 return Val(kind_, impl); 582 } else { 583 return Val(kind_, impl_); 584 } 585 } 586 }; 587 588 589 template<> inline auto Val::make<int32_t>(int32_t x) -> Val { return Val(x); } 590 template<> inline auto Val::make<int64_t>(int64_t x) -> Val { return Val(x); } 591 template<> inline auto Val::make<float32_t>(float32_t x) -> Val { return Val(x); } 592 template<> inline auto Val::make<float64_t>(float64_t x) -> Val { return Val(x); } 593 template<> inline auto Val::make<Ref>(own<Ref>&& x) -> Val { 594 return Val(std::move(x)); 595 } 596 597 template<> inline auto Val::make<uint32_t>(uint32_t x) -> Val { 598 return Val(static_cast<int32_t>(x)); 599 } 600 template<> inline auto Val::make<uint64_t>(uint64_t x) -> Val { 601 return Val(static_cast<int64_t>(x)); 602 } 603 604 template<> inline auto Val::get<int32_t>() const -> int32_t { return i32(); } 605 template<> inline auto Val::get<int64_t>() const -> int64_t { return i64(); } 606 template<> inline auto Val::get<float32_t>() const -> float32_t { return f32(); } 607 template<> inline auto Val::get<float64_t>() const -> float64_t { return f64(); } 608 template<> inline auto Val::get<Ref*>() const -> Ref* { return ref(); } 609 610 template<> inline auto Val::get<uint32_t>() const -> uint32_t { 611 return static_cast<uint32_t>(i32()); 612 } 613 template<> inline auto Val::get<uint64_t>() const -> uint64_t { 614 return static_cast<uint64_t>(i64()); 615 } 616 617 618 // Traps 619 620 using Message = vec<byte_t>; // null terminated 621 622 class Instance; 623 624 class WASM_API_EXTERN Frame { 625 friend class destroyer; 626 void destroy(); 627 628 protected: 629 Frame() = default; 630 ~Frame() = default; 631 632 public: 633 auto copy() const -> own<Frame>; 634 635 auto instance() const -> Instance*; 636 auto func_index() const -> uint32_t; 637 auto func_offset() const -> size_t; 638 auto module_offset() const -> size_t; 639 }; 640 641 class WASM_API_EXTERN Trap : public Ref { 642 friend class destroyer; 643 void destroy(); 644 645 protected: 646 Trap() = default; 647 ~Trap() = default; 648 649 public: 650 static auto make(Store*, const Message& msg) -> own<Trap>; 651 auto copy() const -> own<Trap>; 652 653 auto message() const -> Message; 654 auto origin() const -> own<Frame>; // may be null 655 auto trace() const -> ownvec<Frame>; // may be empty, origin first 656 }; 657 658 659 // Modules 660 661 template<class T> class WASM_API_EXTERN Shared; 662 663 class WASM_API_EXTERN Module : public Ref { 664 friend class destroyer; 665 void destroy(); 666 667 protected: 668 Module() = default; 669 ~Module() = default; 670 671 public: 672 static auto validate(Store*, const vec<byte_t>& binary) -> bool; 673 static auto make(Store*, const vec<byte_t>& binary) -> own<Module>; 674 auto copy() const -> own<Module>; 675 676 auto imports() const -> ownvec<ImportType>; 677 auto exports() const -> ownvec<ExportType>; 678 679 auto share() const -> own<Shared<Module>>; 680 static auto obtain(Store*, const Shared<Module>*) -> own<Module>; 681 682 auto serialize() const -> vec<byte_t>; 683 static auto deserialize(Store*, const vec<byte_t>&) -> own<Module>; 684 }; 685 686 687 // Shared objects 688 689 template<> 690 class WASM_API_EXTERN Shared<Module> { 691 friend class destroyer; 692 void destroy(); 693 694 protected: 695 Shared() = default; 696 ~Shared() = default; 697 }; 698 699 700 // Foreign Objects 701 702 class WASM_API_EXTERN Foreign : public Ref { 703 friend class destroyer; 704 void destroy(); 705 706 protected: 707 Foreign() = default; 708 ~Foreign() = default; 709 710 public: 711 static auto make(Store*) -> own<Foreign>; 712 auto copy() const -> own<Foreign>; 713 }; 714 715 716 // Externals 717 718 class Func; 719 class Global; 720 class Table; 721 class Memory; 722 723 class WASM_API_EXTERN Extern : public Ref { 724 friend class destroyer; 725 void destroy(); 726 727 protected: 728 Extern() = default; 729 ~Extern() = default; 730 731 public: 732 auto copy() const -> own<Extern>; 733 734 auto kind() const -> ExternKind; 735 auto type() const -> own<ExternType>; 736 737 auto func() -> Func*; 738 auto global() -> Global*; 739 auto table() -> Table*; 740 auto memory() -> Memory*; 741 742 auto func() const -> const Func*; 743 auto global() const -> const Global*; 744 auto table() const -> const Table*; 745 auto memory() const -> const Memory*; 746 }; 747 748 749 // Function Instances 750 751 class WASM_API_EXTERN Func : public Extern { 752 friend class destroyer; 753 void destroy(); 754 755 protected: 756 Func() = default; 757 ~Func() = default; 758 759 public: 760 using callback = auto (*)(const vec<Val>&, vec<Val>&) -> own<Trap>; 761 using callback_with_env = auto (*)(void*, const vec<Val>&, vec<Val>&) -> own<Trap>; 762 763 static auto make(Store*, const FuncType*, callback) -> own<Func>; 764 static auto make(Store*, const FuncType*, callback_with_env, 765 void*, void (*finalizer)(void*) = nullptr) -> own<Func>; 766 auto copy() const -> own<Func>; 767 768 auto type() const -> own<FuncType>; 769 auto param_arity() const -> size_t; 770 auto result_arity() const -> size_t; 771 772 auto call(const vec<Val>&, vec<Val>&) const -> own<Trap>; 773 }; 774 775 776 // Global Instances 777 778 class WASM_API_EXTERN Global : public Extern { 779 friend class destroyer; 780 void destroy(); 781 782 protected: 783 Global() = default; 784 ~Global() = default; 785 786 public: 787 static auto make(Store*, const GlobalType*, const Val&) -> own<Global>; 788 auto copy() const -> own<Global>; 789 790 auto type() const -> own<GlobalType>; 791 auto get() const -> Val; 792 void set(const Val&); 793 }; 794 795 796 // Table Instances 797 798 class WASM_API_EXTERN Table : public Extern { 799 friend class destroyer; 800 void destroy(); 801 802 protected: 803 Table() = default; 804 ~Table() = default; 805 806 public: 807 using size_t = uint32_t; 808 809 static auto make( 810 Store*, const TableType*, const Ref* init = nullptr) -> own<Table>; 811 auto copy() const -> own<Table>; 812 813 auto type() const -> own<TableType>; 814 auto get(size_t index) const -> own<Ref>; 815 auto set(size_t index, const Ref*) -> bool; 816 auto size() const -> size_t; 817 auto grow(size_t delta, const Ref* init = nullptr) -> bool; 818 }; 819 820 821 // Memory Instances 822 823 class WASM_API_EXTERN Memory : public Extern { 824 friend class destroyer; 825 void destroy(); 826 827 protected: 828 Memory() = default; 829 ~Memory() = default; 830 831 public: 832 static auto make(Store*, const MemoryType*) -> own<Memory>; 833 auto copy() const -> own<Memory>; 834 835 using pages_t = uint32_t; 836 837 static const size_t page_size = 0x10000; 838 839 auto type() const -> own<MemoryType>; 840 auto data() const -> byte_t*; 841 auto data_size() const -> size_t; 842 auto size() const -> pages_t; 843 auto grow(pages_t delta) -> bool; 844 }; 845 846 847 // Module Instances 848 849 class WASM_API_EXTERN Instance : public Ref { 850 friend class destroyer; 851 void destroy(); 852 853 protected: 854 Instance() = default; 855 ~Instance() = default; 856 857 public: 858 static auto make( 859 Store*, const Module*, const vec<Extern*>&, own<Trap>* = nullptr 860 ) -> own<Instance>; 861 auto copy() const -> own<Instance>; 862 863 auto exports() const -> ownvec<Extern>; 864 }; 865 866 867 /////////////////////////////////////////////////////////////////////////////// 868 869 } // namespace wasm 870 871 #endif // #ifdef WASM_HH 872