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