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